Skip to content

System Overview ​

Complete system architecture diagram and component descriptions.

Full System Diagram ​

Full System Architecture

Clients → Cloudflare Edge → Storage → Provider Registry (Gemini Flash, Gemini Pro, OpenAI gpt-image-2)

Component Details ​

Client Layer ​

ComponentProtocolPurpose
Claude.ai / Claude DesktopMCP over Streamable HTTP or STDIO proxyAI assistant integration
Claude Code / CodexMCP over Streamable HTTP or STDIO proxyCoding-agent integration
Cursor / VS CodeMCP over Streamable HTTP or STDIO proxyCode editor integration
Web ConsoleREST over HTTPSBrowser-based management
REST ClientREST over HTTPSCustom integrations

Edge Layer ​

Worker (src/index.ts) ​

The entry point for all requests:

typescript
export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext) {
    // 1. Parse request
    // 2. Authenticate
    // 3. Route to handler
  }
}

Responsibilities:

  • Parse incoming HTTP requests
  • Extract and validate API keys or OAuth bearer tokens, depending on route
  • Route to appropriate handlers
  • Handle CORS and errors

Auth Middleware (src/auth/) ​

Authentication and authorization:

Authentication Flow

Check cache, query D1, decrypt key, cache result

Durable Objects (src/mcp/agent.ts) ​

Stateful MCP handling:

typescript
export class GoBananasMcpAgent extends DurableObject {
  private server: Server;
  private tenant: ResolvedTenant;
  private sessionId: string;

  async fetch(request: Request) {
    // Handle MCP protocol
  }
}

Responsibilities:

  • Maintain session state
  • Execute MCP tools
  • Track last_image_id
  • Return formatted responses

Storage Layer ​

D1 Database ​

SQLite database with these tables:

TablePurposeKey Fields
tenantsTenant configurationtenant_id, encrypted_gemini_key, allowed_models
tenant_provider_credentialsPer-provider keys (Gemini, OpenAI)tenant_id, provider, encrypted_key
api_keysAPI key mappingsapi_key, tenant_id
usersUser accountsemail, role
imagesImage metadatar2_key, prompt, parent_image_id
sessionsSession statelast_image_id, total_images
charactersCharacter librarybase_prompt, reference_image_ids
character_videosCharacter video refscharacter_id, r2_key
product_referencesProduct refsproduct_url, r2_key
reference_groupsReusable image groupsgroup_name, reference_image_ids
scene_presetsScene presetsscene_prompt, reference_image_ids
style_presetsStyle templatesprompt, negative_prompt
search_presetsSaved search filtersname, filters
usage_logsAnalytics dataoperation, images_generated
tool_execution_logsExecution trackingtool_name, status
tenant_webhooksWebhook endpointsurl, events
quota_notificationsQuota alert dedupthreshold, billing_period

R2 Bucket ​

Object storage with structure:

go-bananas-images/
├── tenant_abc123/
│   ├── 2024-01-15/
│   │   ├── generate-xyz789.png
│   │   ├── generate-xyz789-thumb.jpg
│   │   └── edit-abc456.png
│   └── 2024-01-14/
│       └── ...
└── tenant_def456/
    └── ...

KV Store ​

Fast key-value lookups:

NamespaceKey PatternValue
API_KEYSsk_live_xxxtenant_id
TENANT_CONFIGtenant:{id}Tenant JSON

External Services ​

Image Provider Registry ​

The provider abstraction (src/services/image-provider/) routes each generation request to the appropriate API based on the tenant's selected model_id. Two providers ship today, serving six models:

ProviderModelsEndpoint patternDefault timeout
Geminigemini-flash-lite-image (default), gemini-flash-image, gemini-pro-imageGoogle AI Studio (generativelanguage.googleapis.com)30s / 60s / 120s
OpenAIopenai-gpt-image-2, openai-gpt-image-2.5-flare, openai-gpt-image-2.5-sunburstapi.openai.com/v1/images/{generations,edits}240s

Each provider implements the same ImageProviderClient contract — generate, edit, testConnection, getModelInfo — and is wrapped with a per-key circuit breaker, exponential-backoff retry, and aspect-ratio enforcement. Adding a new provider is a matter of dropping a new file into src/services/image-provider/ and registering the model in src/models/registry.ts.

Eight-step request lifecycle

Eight steps from HTTP request to response — step 6 is where the registry picks Gemini or OpenAI based on the tenant's `model_id`.

Data Relationships ​

Data Relationships ER Diagram

Tenant owns all resources with complete isolation

Deployment Topology ​

Global Deployment Topology

Edge workers worldwide with centralized D1 and R2 storage

Configuration Files ​

FilePurpose
wrangler.jsoncCloudflare Worker config
schema.sqlDatabase schema
package.jsonDependencies
tsconfig.jsonTypeScript config

Next Steps ​

Released under the MIT License.