ONLINE EDITING ARCHITECTURE

Documentation for Sessions

Online Editing Architecture - MongoDB Sync Workflow

Date: January 5, 2026
Time: 4:30 PM PST
Session ID: gspace-1.1
Status: 📋 ARCHITECTURE DESIGN
Purpose: Enable online documentation editing with MongoDB sync to local /docs folder
Confidence Level: 99%


🎯 The Complete Picture

You asked: "How can we create/upload online, directly into MongoDB, and then sync to the real database (our /docs folder)?"

Answer: This is exactly what backend-docs-api was designed for! Here's the complete workflow:


📊 Current vs. Desired Architecture

Current (Production) ✅

User Browser
    ↓
docs-angular (static files)
    ↓
/docs folder (bundled at build time)
    ↓
Fast, reliable, no database

Benefits: 10-50ms load time, works offline, no network dependency


Desired (With Online Editing) 🚀

┌─────────────────────────────────────────────────────────────┐
│                  BIDIRECTIONAL SYNC WORKFLOW                 │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  📝 Online Editor (docs-angular)                           │
│      ↓                                                      │
│  🌐 backend-docs-api (Port 3002)                           │
│      ↓                                                      │
│  🗄️  MongoDB (test-modules cluster)                        │
│      - docs-database                                        │
│      - Collections: doc-files, doc-projects                │
│                                                             │
│  ← SYNC BACK ←                                             │
│                                                             │
│  📥 Node.js Sync Script                                    │
│      ↓                                                      │
│  📁 Local /docs Folder                                     │
│      ↓                                                      │
│  🚀 Deploy with App                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Benefits: Online editing + Static file performance + Version control


🏗️ Complete Architecture

Components

Component Purpose Status Port
docs-angular Frontend viewer/editor ✅ Running 5010
backend-docs-api MongoDB CRUD API ⚠️ Disabled 3002
MongoDB (test-modules) Online storage ✅ Active 27017
watch-docs-changes.js Local → MongoDB sync ⚠️ Disabled N/A
sync-from-mongodb.js MongoDB → Local sync ❌ Not created N/A

🔄 The Complete Workflow

Phase 1: Local Development (Upload to Cloud)

1. Edit local /docs files
   ↓
2. watch-docs-changes.js detects changes
   ↓
3. POST to backend-docs-api /sync/files
   ↓
4. Saves to MongoDB (docs-database)
   ↓
5. WebSocket broadcasts change to all clients
   ↓
6. Other developers get real-time updates

Phase 2: Online Editing (Create in MongoDB)

1. User opens docs-angular admin panel
   ↓
2. Creates/edits documentation online
   ↓
3. POST to backend-docs-api /sync/files
   ↓
4. Saves to MongoDB (docs-database)
   ↓
5. Immediately available to all users
   ↓
6. Syncs back to local /docs folder (Phase 3)

Phase 3: Sync Back to Local (Deploy)

1. Run sync script: yarn docs:sync-from-cloud
   ↓
2. GET from backend-docs-api /sync/files
   ↓
3. Downloads all files from MongoDB
   ↓
4. Writes to local /docs folder
   ↓
5. Git commit and push
   ↓
6. Deploy app with updated /docs folder

📝 Implementation Steps

Step 1: Enable backend-docs-api

File: apps/docs-angular/src/environments/environment.ts

export const environment = {
  production: false,
  // ✅ Enable backend-docs-api
  docsApiUrl: 'http://localhost:3002/docs-api',
  wsUrl: 'ws://localhost:3002',
  enableCloudSync: true, // Enable cloud sync
  enableAnalytics: true, // Enable analytics
};

File: apps/docs-angular/src/environments/environment.prod.ts

export const environment = {
  production: true,
  // ✅ Use production backend-docs-api
  docsApiUrl: 'https://backend-docs-api-production.up.railway.app/docs-api',
  wsUrl: 'wss://backend-docs-api-production.up.railway.app',
  enableCloudSync: true,
  enableAnalytics: true,
};

Step 2: Start backend-docs-api

# Install dependencies (if not already)
yarn install

# Start backend-docs-api
yarn serve:backend-docs

# Or start all backends together
yarn dev:all-backends

Expected Output:

📚 GoGrab Backend Docs API READY on port 3002
📡 Server:      http://localhost:3002/docs-api
🗄️  Database:    docs-database (test-modules cluster)
📄 Collections:  doc-files, doc-projects, analytics

Step 3: Enable Local → MongoDB Sync

# Watch for changes and sync to MongoDB
yarn docs:watch

# Or run manually
ENABLE_CLOUD_SYNC=true node apps/docs-angular/scripts/watch-docs-changes.js

What it does:


Step 4: Initial Bulk Upload

Upload all existing docs to MongoDB:

# Bulk sync all docs to cloud
yarn docs:sync

# Or run manually
node apps/docs-angular/scripts/sync-to-cloud.js

What it does:


Step 5: Create Online Editor UI

File: apps/docs-angular/src/app/admin/doc-editor/doc-editor.component.ts (NEW)

import { Component, signal, inject } from '@angular/core';
import { DocsApiService } from '../../services/docs-api.service';
import { autoFlashState } from '@storage-system';

@Component({
  selector: 'app-doc-editor',
  standalone: true,
  template: `
    <div class="editor-container">
      <h2>Create/Edit Documentation</h2>
      
      <!-- File Path -->
      <input
        type="text"
        [(ngModel)]="filePath"
        placeholder="english/MyProject/my-doc.md"
        class="path-input" />
      
      <!-- Markdown Editor -->
      <textarea
        [(ngModel)]="content"
        placeholder="# My Documentation\n\nContent here..."
        class="markdown-editor"
        rows="20"></textarea>
      
      <!-- Save Button -->
      <button (click)="saveToMongoDB()" [disabled]="isSaving()">
        {{ isSaving() ? 'Saving...' : 'Save to MongoDB' }}
      </button>
      
      @if (saveResult()) {
        <div class="save-result">{{ saveResult() }}</div>
      }
    </div>
  `,
  styles: [`
    .editor-container {
      max-width: 1200px;
      margin: 0 auto;
      padding: 2rem;
    }
    .path-input, .markdown-editor {
      width: 100%;
      padding: 1rem;
      margin: 1rem 0;
      border: 1px solid #ccc;
      border-radius: 8px;
    }
    .markdown-editor {
      font-family: 'Monaco', monospace;
      font-size: 14px;
    }
    button {
      padding: 1rem 2rem;
      background: #4f46e5;
      color: white;
      border: none;
      border-radius: 8px;
      cursor: pointer;
    }
    button:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
  `]
})
export class DocEditorComponent {
  private readonly docsApi = inject(DocsApiService);
  
  // Editor state (persisted)
  readonly filePath = autoFlashState<string>('editor-file-path', '');
  readonly content = autoFlashState<string>('editor-content', '');
  
  readonly isSaving = signal(false);
  readonly saveResult = signal('');
  
  async saveToMongoDB() {
    if (!this.filePath() || !this.content()) {
      this.saveResult.set('⚠️ Path and content are required');
      return;
    }
    
    this.isSaving.set(true);
    this.saveResult.set('');
    
    try {
      // Extract frontmatter metadata
      const metadata = this.extractFrontmatter(this.content());
      
      // Save to MongoDB via backend-docs-api
      const result = await this.docsApi.upsertFile({
        path: this.filePath(),
        content: this.content(),
        metadata: {
          ...metadata,
          language: this.detectLanguage(this.filePath()),
          project: this.detectProject(this.filePath()),
        }
      });
      
      console.log('✅ Saved to MongoDB:', result);
      this.saveResult.set(`✅ Saved successfully! Version ${result.version}`);
      
    } catch (error) {
      console.error('❌ Save failed:', error);
      this.saveResult.set(`❌ Save failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    } finally {
      this.isSaving.set(false);
    }
  }
  
  private extractFrontmatter(content: string): any {
    const match = content.match(/^---\n([\s\S]*?)\n---/);
    if (!match) return {};
    
    const frontmatter = match[1];
    const metadata: any = {};
    const lines = frontmatter.split('\n');
    
    for (const line of lines) {
      const colonIndex = line.indexOf(':');
      if (colonIndex > 0) {
        const key = line.substring(0, colonIndex).trim();
        const value = line.substring(colonIndex + 1).trim().replace(/^["']|["']$/g, '');
        metadata[key] = value;
      }
    }
    
    return metadata;
  }
  
  private detectLanguage(path: string): string {
    return path.includes('/english/') ? 'en' : path.includes('/spanish/') ? 'es' : 'en';
  }
  
  private detectProject(path: string): string {
    const parts = path.split('/');
    const langIndex = parts.findIndex(p => p === 'english' || p === 'spanish');
    return langIndex >= 0 && langIndex + 1 < parts.length ? parts[langIndex + 1] : 'public';
  }
}

Add Route:

// apps/docs-angular/src/app/app.routes.ts
{
  path: 'admin/editor',
  loadComponent: () => import('./admin/doc-editor/doc-editor.component').then(m => m.DocEditorComponent),
  title: 'Documentation Editor'
}

Step 6: Create MongoDB → Local Sync Script

File: apps/docs-angular/scripts/sync-from-mongodb.js (NEW)

#!/usr/bin/env node

/**
 * 📥 SYNC FROM MONGODB TO LOCAL
 *
 * Downloads all documentation files from MongoDB and writes them
 * to the local /docs folder for deployment.
 *
 * Usage: node scripts/sync-from-mongodb.js
 */

const fs = require('fs');
const path = require('path');

// MongoDB/API Configuration
const DOCS_API_URL = process.env.DOCS_API_URL || 'http://localhost:3002/docs-api';
const SYSTEM_TOKEN = process.env.SYSTEM_TOKEN || '';

// Local docs path
const DOCS_BASE_PATH = path.join(process.cwd(), 'docs');

/**
 * Fetch all files from MongoDB
 */
async function fetchAllFiles() {
  console.log('📥 Fetching files from MongoDB...');
  
  const response = await fetch(`${DOCS_API_URL}/sync/files?limit=1000`, {
    headers: {
      ...(SYSTEM_TOKEN ? { 'Authorization': `Bearer ${SYSTEM_TOKEN}` } : {})
    }
  });
  
  if (!response.ok) {
    throw new Error(`Failed to fetch files: ${response.statusText}`);
  }
  
  const data = await response.json();
  console.log(`📋 Found ${data.files.length} files in MongoDB`);
  
  return data.files;
}

/**
 * Write file to local filesystem
 */
function writeFileToLocal(file) {
  const fullPath = path.join(DOCS_BASE_PATH, file.path);
  const dir = path.dirname(fullPath);
  
  // Create directory if it doesn't exist
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  
  // Write file content
  fs.writeFileSync(fullPath, file.content, 'utf8');
  console.log(`✅ Wrote: ${file.path}`);
}

/**
 * Main sync function
 */
async function syncFromMongoDB() {
  console.log('╔════════════════════════════════════════╗');
  console.log('║  📥 Sync from MongoDB to Local        ║');
  console.log('╚════════════════════════════════════════╝');
  console.log('');
  console.log(`📁 Local path: ${DOCS_BASE_PATH}`);
  console.log(`🌐 API URL: ${DOCS_API_URL}`);
  console.log('');
  
  try {
    // Fetch all files
    const files = await fetchAllFiles();
    
    if (files.length === 0) {
      console.log('⚠️ No files found in MongoDB');
      return;
    }
    
    // Write files to local
    let successCount = 0;
    let errorCount = 0;
    
    for (const file of files) {
      try {
        writeFileToLocal(file);
        successCount++;
      } catch (error) {
        console.error(`❌ Failed to write ${file.path}:`, error.message);
        errorCount++;
      }
    }
    
    console.log('');
    console.log('╔════════════════════════════════════════╗');
    console.log('║  ✅ Sync Complete                     ║');
    console.log('╚════════════════════════════════════════╝');
    console.log('');
    console.log(`✅ Success: ${successCount} files`);
    console.log(`❌ Errors:  ${errorCount} files`);
    console.log('');
    
    if (errorCount === 0) {
      console.log('🚀 Ready to commit and deploy!');
    }
    
  } catch (error) {
    console.error('');
    console.error('❌ Sync failed:', error);
    process.exit(1);
  }
}

// Run if called directly
if (require.main === module) {
  syncFromMongoDB()
    .then(() => process.exit(0))
    .catch((error) => {
      console.error('❌ Fatal error:', error);
      process.exit(1);
    });
}

module.exports = { syncFromMongoDB };

Add to package.json:

{
  "scripts": {
    "docs:sync-from-cloud": "node apps/docs-angular/scripts/sync-from-mongodb.js",
    "docs:sync": "node apps/docs-angular/scripts/sync-to-cloud.js",
    "docs:watch": "node apps/docs-angular/scripts/watch-docs-changes.js"
  }
}

🔐 backend-docs-api Endpoints

File Operations

Endpoint Method Auth Purpose
/sync/files GET Public List all files
/sync/files/:path GET Public Get single file
/sync/files POST JWT Create/update file
/sync/files/:path DELETE JWT Delete file
/sync/bulk POST JWT Bulk upload

Project Operations

Endpoint Method Auth Purpose
/sync/projects GET Public List projects
/admin/projects POST JWT Create project

Real-time Updates

WebSocket: ws://localhost:3002/docs-sync

Events:


📊 Data Flow Examples

Example 1: Create Documentation Online

// 1. User fills out online editor
const newDoc = {
  path: 'english/MyProject/getting-started.md',
  content: `---
title: Getting Started
description: Quick start guide
---

# Getting Started

Welcome to MyProject!`,
  metadata: {
    title: 'Getting Started',
    description: 'Quick start guide',
    language: 'en',
    project: 'MyProject'
  }
};

// 2. Save to MongoDB via backend-docs-api
const response = await fetch('http://localhost:3002/docs-api/sync/files', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${jwtToken}`
  },
  body: JSON.stringify(newDoc)
});

// 3. MongoDB saves document
{
  path: 'english/MyProject/getting-started.md',
  content: '...',
  metadata: {...},
  contentHash: 'sha256...',
  version: 1,
  createdAt: ISODate('2026-01-05T...'),
  updatedAt: ISODate('2026-01-05T...')
}

// 4. WebSocket broadcasts to all clients
socket.emit('file-change', {
  event: 'created',
  file: { path: 'english/MyProject/getting-started.md', ... },
  timestamp: '2026-01-05T...'
});

// 5. All connected clients receive update
// Users see new documentation immediately!

Example 2: Sync Back to Local

# Run sync script
yarn docs:sync-from-cloud

# Output:
📥 Fetching files from MongoDB...
📋 Found 247 files in MongoDB
✅ Wrote: english/MyProject/getting-started.md
✅ Wrote: english/MyProject/advanced-guide.md
... (247 files total)
✅ Sync Complete
🚀 Ready to commit and deploy!

# Commit and push
git add docs/
git commit -m "docs: synced from MongoDB"
git push

# Deploy app
# New documentation is now bundled with the app!

🎯 Use Cases

Use Case 1: Technical Writer (Online Editing)

1. Navigate to gograb.space/docs/admin/editor
2. Create new documentation file
3. Write content in markdown
4. Click "Save to MongoDB"
5. Documentation immediately available to all users
6. Periodic sync to local /docs folder
7. Deploy with next release

Benefits:

Use Case 2: Developer (Local Editing)

1. Edit files in local /docs folder
2. watch-docs-changes.js auto-syncs to MongoDB
3. Changes immediately available online
4. Other developers get real-time updates
5. Commit to git as usual

Benefits:

Use Case 3: Deployment (Production Build)

1. Run: yarn docs:sync-from-cloud
2. Downloads all files from MongoDB
3. Writes to local /docs folder
4. Git commit and push
5. Deploy app with nx build docs-angular
6. Static files bundled with app (fast!)

Benefits:


🔒 Security Considerations

Authentication

JWT Tokens: backend-docs-api uses shared JWT with backend-api

// Get JWT token
const token = await authService.login(username, password);

// Use in requests
const response = await fetch('http://localhost:3002/docs-api/sync/files', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(fileData)
});

Permissions

Public Endpoints (READ):

Protected Endpoints (WRITE):


📈 Performance Comparison

Scenario Static Files MongoDB + Sync Difference
First Load 10-50ms 10-50ms Same (static after sync)
Edit Online ❌ Not possible ✅ Instant N/A
Real-time Collab ❌ Not possible ✅ WebSocket N/A
Offline Mode ✅ Works ⚠️ Online only Static wins
Version Control ✅ Git ✅ MongoDB + Git Both
Deployment Simple +1 sync step Minimal overhead

🚀 Getting Started Checklist

Prerequisites

Setup Steps

  1. Update environment.ts - Enable docsApiUrl
  2. Update environment.prod.ts - Add production API URL
  3. Start backend-docs-api: yarn serve:backend-docs
  4. Run initial bulk sync: yarn docs:sync
  5. Enable file watcher: yarn docs:watch
  6. Create online editor UI component
  7. Test end-to-end workflow
  8. Deploy to production

Estimated Time: 2-4 hours to enable and test


💡 Recommendations

Immediate Actions (High Priority)

  1. Enable backend-docs-api (30 min)

    • Update environment files
    • Start the API locally
    • Test connectivity
  2. Run Initial Sync (15 min)

    • Bulk upload existing docs to MongoDB
    • Verify data in MongoDB Compass
    • Test retrieval
  3. Create Online Editor (2 hours)

    • Build simple markdown editor UI
    • Integrate with backend-docs-api
    • Test create/update/delete
  4. Create Sync-Back Script (1 hour)

    • Implement sync-from-mongodb.js
    • Test download and write to local
    • Add to deployment workflow

Long-term Improvements

  1. Conflict Resolution

    • Handle simultaneous edits
    • Implement version merging
    • Add conflict UI
  2. Advanced Editor

    • Live markdown preview
    • Syntax highlighting
    • Auto-save drafts
    • Image upload
  3. Collaboration Features

    • Real-time cursors
    • Comments and reviews
    • Approval workflow
    • Change notifications
  4. Automation

    • Auto-sync on deploy
    • Scheduled backups
    • CI/CD integration
    • Automatic git commits

📚 Related Documentation


🎯 Key Takeaways

  1. docs-angular is MongoDB-free by design - For optimal production performance
  2. backend-docs-api enables online editing - Optional feature, currently disabled
  3. Bidirectional sync is the key - Local ↔ MongoDB ↔ Local
  4. Best of both worlds - Online editing + Static file performance
  5. Already built, just needs enabling - Most code already exists!

Architecture Complete: ✅
Confidence Level: 99%
Implementation Difficulty: Medium (2-4 hours)
Production Ready: After testing


Designed by AI Agent - Session gspace-1.1
Date: January 5, 2026
Time: 4:30 PM PST