Skip to content

High-Performance Multi-User Bookmark Manager with Enterprise Patterns (Redis-like Cache, Kafka-like Event Bus, Virtual Actor Model)

Notifications You must be signed in to change notification settings

Psarrokos/SROBY

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”– SROBY β€” High-Performance Multi-User Bookmark Manager

Version Platform License Users

A blazing-fast, real-time synchronized bookmark manager built on Google Apps Script

Features β€’ Architecture β€’ Installation β€’ API Reference β€’ Performance


πŸ“‹ Overview

SROBY is an ultra-fast, multi-user bookmark manager designed for teams and power users who need to organize thousands of bookmarks with real-time synchronization across devices. Built entirely on Google Apps Script, it requires zero server infrastructure while supporting 25+ concurrent users with instant sync.

Why SROBY?

  • πŸš€ Optimized for scale: Handles 2,000+ bookmarks without breaking a sweat
  • πŸ‘₯ Multi-user ready: 25 concurrent users with zero conflicts
  • ⚑ Real-time sync: Changes propagate to all users within 1-2 seconds
  • πŸ†“ Zero cost: Runs entirely on Google's free infrastructure
  • πŸ”’ Secure: Google account authentication built-in

✨ Features

Core Functionality

Feature Description
Categories Organize bookmarks into collapsible categories
Tags Add multiple tags per bookmark for flexible organization
Search Multi-word search across names, URLs, and tags
Info/Notes Add descriptions and notes to any bookmark
Favicons Automatic favicon fetching for visual identification

User Experience

Feature Description
Drag & Drop Reorder bookmarks within categories via drag and drop
Cross-Category Move Drag bookmarks between different categories
Open All One-click to open all bookmarks in a category
Inline Edit Edit bookmarks without leaving the main view
Smart URL Auto-adds https:// and .com when needed

Real-Time Collaboration

Feature Description
Instant Sync Changes sync across all users within 1-2 seconds
User Attribution See who made the last change
Conflict Prevention LockService prevents simultaneous write conflicts
Active Users See how many users are currently active

Reliability

Feature Description
Optimistic UI Instant visual feedback before server confirmation
Auto-Rollback Automatic restoration on save failure
Offline Detection Graceful degradation with cached data
Connection Recovery Auto-reconnects and syncs when connection returns

πŸ— Architecture

System Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        FRONTEND (index.html)                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚   Dark UI   β”‚  β”‚   Search    β”‚  β”‚   Drag & Drop Manager   β”‚  β”‚
β”‚  β”‚  (CSS Vars) β”‚  β”‚   Engine    β”‚  β”‚   (Reorder/Move)        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚              Request Queue (Priority-based)                  β”‚β”‚
β”‚  β”‚         β€’ Deduplication β€’ Retry Logic β€’ Throttling          β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚              Event Bus (Pub/Sub Pattern)                     β”‚β”‚
β”‚  β”‚    β€’ Persistence β€’ Cross-component Communication            β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                              β”‚
                    google.script.run
                              β”‚
                              β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      BACKEND (Code.gs)                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚
β”‚  β”‚                    CACHING LAYERS                            β”‚β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚β”‚
β”‚  β”‚  β”‚ L1: Redis β”‚ => β”‚ L2: Scriptβ”‚ => β”‚ L3: Properties    β”‚   β”‚β”‚
β”‚  β”‚  β”‚   -like   β”‚    β”‚   Cache   β”‚    β”‚    Service        β”‚   β”‚β”‚
β”‚  β”‚  β”‚  (6h TTL) β”‚    β”‚  (6h TTL) β”‚    β”‚   (Persistent)    β”‚   β”‚β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  LockService β”‚  β”‚   Chunking   β”‚  β”‚ Change Notifications β”‚  β”‚
β”‚  β”‚  (Conflicts) β”‚  β”‚  (>9KB data) β”‚  β”‚   (Real-time sync)   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Frontend Components

1. Request Queue System

Manages all backend communication with intelligent prioritization:

Priority Levels:
β”œβ”€β”€ 10 (Critical)  β†’ Save operations, deletions
β”œβ”€β”€ 8  (High)      β†’ User-initiated updates
β”œβ”€β”€ 5  (Normal)    β†’ Standard CRUD operations
└── 1  (Low)       β†’ Background sync, polling

Features:

  • Deduplication: Prevents duplicate requests
  • Retry Logic: Auto-retries with exponential backoff
  • Throttling: Max 3 concurrent requests
  • Queue Limit: 20 items max, drops lowest priority when full

2. Event Bus

Pub/sub system for component communication:

Events:
β”œβ”€β”€ dataLoaded      β†’ Initial data fetch complete
β”œβ”€β”€ bookmarkAdded   β†’ New bookmark created
β”œβ”€β”€ bookmarkUpdated β†’ Bookmark modified
β”œβ”€β”€ bookmarkDeleted β†’ Bookmark removed
β”œβ”€β”€ categoryAdded   β†’ New category created
β”œβ”€β”€ syncComplete    β†’ Real-time sync finished
└── connectionError β†’ Backend communication failed

3. Status Indicator

Real-time visual feedback system:

Status Color Meaning
Ready 🟒 Green Connected, all synced
Syncing πŸ”΅ Blue Fetching/sending data
Saving 🟣 Purple Write operation in progress
Warning 🟑 Yellow Slow connection detected
Error πŸ”΄ Red Operation failed
Offline ⚫ Gray No connection

Backend Components

1. Multi-Layer Caching

Request Flow:
─────────────────────────────────────────────────────────
     L1 Cache Hit?
          β”‚
    β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
    β”‚Yes        β”‚No
    β–Ό           β–Ό
  Return    L2 Cache Hit?
    β”‚           β”‚
    β”‚     β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
    β”‚     β”‚Yes        β”‚No
    β”‚     β–Ό           β–Ό
    β”‚   Return    Read from
    β”‚     β”‚       Properties
    β”‚     β”‚           β”‚
    β”‚     β”‚     Populate L1+L2
    β”‚     β”‚           β”‚
    β””β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Cache Configuration:

  • CACHE_DURATION: 6 hours (21,600 seconds) - Google's maximum
  • SHORT_CACHE: 5 minutes (300 seconds) - for frequently changing data
  • MAX_CHUNK_SIZE: 8,000 bytes - safe limit under 9KB quota

2. Data Chunking

Handles large datasets that exceed Google's 9KB property limit:

// Automatic chunking for large datasets
if (jsonData.length > 8000) {
    // Split into multiple chunks
    for (i = 0; i < jsonData.length; i += 8000) {
        chunks.push(jsonData.substring(i, i + 8000));
    }
}
// Store: SRO_CHUNK_0, SRO_CHUNK_1, SRO_CHUNK_2...

3. LockService

Prevents concurrent write conflicts:

var lock = LockService.getScriptLock();
lock.tryLock(3000); // 3 second timeout

// If lock fails β†’ throw "Busy" error
// Frontend auto-retries with exponential backoff

4. Change Notification System

Enables real-time cross-user synchronization:

// On every write operation:
updateChangeNotification(userId, action);

// Stored as:
{
    timestamp: 1706961234567,
    userId: "john.doe",
    action: "addBookmark"
}

// Frontend polls every 1 second:
if (notification.timestamp > lastKnownChangeTime) {
    // Trigger full sync
    loadBookmarks();
}

πŸ“Š Data Model

Schema

{
    "categories": [
        {
            "id": "cat1706961234567_a1b2c3d4e",
            "name": "Development Tools",
            "bookmarks": [
                {
                    "id": "b1706961234567_x9y8z7w6v",
                    "title": "GitHub",
                    "url": "https://github.com",
                    "tags": ["code", "git", "repos"],
                    "info": "Main code repository"
                },
                {
                    "id": "b1706961234568_m5n4o3p2q",
                    "title": "Stack Overflow",
                    "url": "https://stackoverflow.com",
                    "tags": ["help", "community"],
                    "info": ""
                }
            ]
        }
    ],
    "lastModified": 1706961234567
}

ID Generation

Collision-free IDs using timestamp + random suffix:

// Category ID
"cat" + Date.now() + "_" + Math.random().toString(36).substr(2, 9)
// Example: cat1706961234567_a1b2c3d4e

// Bookmark ID  
"b" + Date.now() + "_" + Math.random().toString(36).substr(2, 9)
// Example: b1706961234567_x9y8z7w6v

Storage Keys

Key Purpose
SRO_META Metadata (chunk count, lastModified, size)
SRO_CHUNK_0..N Data chunks (for large datasets)
SRO_CHANGE_NOTIFICATION Cross-user sync flag

πŸš€ Installation

Prerequisites

Step-by-Step Setup

1. Create New Project

1. Go to https://script.google.com
2. Click "New Project"
3. Name it "SROBY"

2. Add Backend Code

1. In Code.gs (default file), paste contents of Code.gs
2. Save (Ctrl+S)

3. Add Frontend

1. Click + β†’ HTML
2. Name it "index" (creates index.html)
3. Paste contents of index.html
4. Save (Ctrl+S)

4. Deploy as Web App

1. Click "Deploy" β†’ "New deployment"
2. Select type: "Web app"
3. Configure:
   - Description: "SROBY Bookmark Manager"
   - Execute as: "Me"
   - Who has access: "Anyone with Google Account" 
     (or "Anyone" for public access)
4. Click "Deploy"
5. Copy the Web App URL

5. Authorize

1. Open the Web App URL
2. Click "Review Permissions"
3. Select your Google Account
4. Click "Advanced" β†’ "Go to SROBY (unsafe)"
5. Click "Allow"

Update Deployment

When you make changes:

1. Click "Deploy" β†’ "Manage deployments"
2. Click ✏️ (edit) on your deployment
3. Version: "New version"
4. Click "Deploy"

πŸ“š API Reference

Backend Functions (Code.gs)

Data Operations

Function Parameters Returns Description
getBookmarks() - {categories, lastModified} Fetch all data
saveBookmarks(data) {categories, lastModified} {success, lastModified} Save all data
getLastModified() - number Get last update timestamp

Bookmark CRUD

Function Parameters Returns Description
addBookmark(categoryId, bookmark) string, {title, url, tags?, info?} {success, lastModified} Add new bookmark
updateBookmark(categoryId, bookmarkId, updates) string, string, {title?, url?, tags?, info?, newCategoryId?} {success, lastModified} Update bookmark
deleteBookmark(categoryId, bookmarkId) string, string {success, lastModified} Delete bookmark
reorderBookmarks(categoryId, orderedIds) string, string[] {success, lastModified} Reorder bookmarks

Category CRUD

Function Parameters Returns Description
addCategory(name) string {success, lastModified} Create category
updateCategory(categoryId, newName) string, string {success, lastModified} Rename category
deleteCategory(categoryId) string {success, lastModified} Delete category with all bookmarks
getCategoryIndex() - {categories: [{id, name, count}], lastModified} Lightweight category list

Sync & Utilities

Function Parameters Returns Description
getChangeNotification() - {timestamp, userId, action} Get last change info
getUserEmail() - string Get current user's email
getDataSize() - {size, chunks, bookmarks, categories} Storage statistics
getCacheStats() - {redis, legacy, storage} Cache hit/miss stats
clearCache() - {success, message} Invalidate all caches

⚑ Performance

Benchmarks

Metric Value
Initial load (cold cache) ~800-1200ms
Initial load (warm cache) ~150-300ms
Add bookmark ~400-600ms
Delete bookmark ~300-500ms
Sync detection latency ~1000-2000ms
Max bookmarks tested 2,000+
Concurrent users tested 25

Optimizations Implemented

  1. Three-tier caching - L1 (Redis-like) β†’ L2 (Script Cache) β†’ L3 (Properties)
  2. Cache warming - Pre-populate cache after writes
  3. Optimistic UI - Instant visual feedback before server confirmation
  4. Request deduplication - Prevent redundant backend calls
  5. Priority queue - Critical operations execute first
  6. Chunked storage - Handle datasets > 9KB limit
  7. Lightweight polling - 1-second notification checks (not full data)
  8. Background sync - 60-second idle refresh cycle

Quotas & Limits

Resource Limit SROBY Usage
Script Properties 500KB total βœ… Chunking handles large data
Single Property 9KB βœ… 8KB chunks (safe margin)
Cache 100KB per key βœ… Well under limit
Cache TTL 6 hours max βœ… Using maximum
Execution time 6 minutes βœ… Operations < 1 second
Daily triggers 90 min/day βœ… No time-based triggers

🎨 UI/UX Details

Design System

Color Palette (Dark Theme):

--bg:           #0a0e17    /* Main background */
--bg-secondary: #111827    /* Cards, header */
--bg-hover:     #1f2937    /* Hover states */
--text:         #f3f4f6    /* Primary text */
--text-dim:     #9ca3af    /* Secondary text */
--accent:       #3b82f6    /* Primary accent (blue) */
--accent-hover: #60a5fa    /* Accent hover */
--border:       #374151    /* Borders */
--success:      #10b981    /* Success states */
--error:        #ef4444    /* Error states */

Keyboard Shortcuts

Key Action
/ Focus search box
Escape Close modals, clear search

Responsive Breakpoints

@media (max-width: 768px)  β†’ Tablet layout
@media (max-width: 480px)  β†’ Mobile layout

πŸ”§ Troubleshooting

Common Issues

Issue Solution
"Busy" error Another user is saving. Auto-retries in 2-5 seconds.
Changes not syncing Check connection. Try manual refresh (F5).
Slow performance Clear cache via clearCache() in Script Editor.
"Category not found" Data may be stale. Refresh the page.
Favicon not loading Some sites block favicon access. Normal behavior.

Debug Mode

Open browser console (F12) to see detailed logs:

πŸ”„ REAL-TIME SYNC: Change from "john" (action: addBookmark)
⏱️ Latency: 847ms | Active users detected
πŸ“‹ Sync notification received

πŸ“ License

MIT License - feel free to use, modify, and distribute.


🀝 Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Submit a pull request

Built with ❀️ using Google Apps Script

About

High-Performance Multi-User Bookmark Manager with Enterprise Patterns (Redis-like Cache, Kafka-like Event Bus, Virtual Actor Model)

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published