Get started

Architecture Options Report

Analysis of deployment models, admin areas, API key management, team permissions, and multi-tenancy strategy for Quox's enterprise features.

Deployment Models, Key Management, and Multi-Tenancy Strategy

Date: 2026-01-21 Author: Claude (AI Architecture Analysis) Status: Decision Required


Executive Summary

This report analyzes deployment and architecture options for Quox, addressing:

  1. Deployment Model - Self-hosted vs hosted vs hybrid
  2. Admin/Superuser Area - System-level configuration and monitoring
  3. API Key Management - Who controls which keys and how
  4. Team Permissions - User autonomy vs admin control
  5. Future Hosted Service - Architecture decisions to preserve optionality

Recommendation: Adopt a "Self-Hosted First with Hosted Option" model using hierarchical key management with configurable delegation policies.


1. Deployment Model Analysis

Option A: Pure Self-Hosted (Open Source)

Model: Users download and run Quox on their own infrastructure.

Examples: n8n self-hosted, Mattermost self-hosted, GitLab self-managed

Pros:

  • Full data sovereignty and privacy
  • No vendor lock-in
  • Compliance-friendly (HIPAA, GDPR, SOC 2)
  • Community contributions
  • No recurring SaaS costs

Cons:

  • Admin must manage infrastructure
  • Updates/patches are manual
  • Support burden on community/docs
  • No recurring revenue (unless enterprise features)

Revenue Model:

  • Enterprise features (SSO, audit logs, priority support)
  • Paid support contracts
  • Professional services

Option B: Pure Hosted (SaaS)

Model: Quox runs as a hosted service, users sign up online.

Examples: n8n Cloud, GitLab.com

Pros:

  • Recurring revenue (subscriptions)
  • Faster onboarding
  • Automatic updates
  • Centralized monitoring

Cons:

  • Infrastructure costs
  • Data privacy concerns for some users
  • Multi-tenant complexity
  • Support obligations

Model: Primary focus on self-hosted, with optional hosted service for users who want convenience.

Examples:

Implementation:

┌─────────────────────────────────────────────────────────────────┐
│                    QUOX DISTRIBUTION                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌──────────────────┐    ┌──────────────────┐                  │
│   │   SELF-HOSTED    │    │     HOSTED       │                  │
│   │   (Primary)      │    │   (Optional)     │                  │
│   ├──────────────────┤    ├──────────────────┤                  │
│   │ • Open source    │    │ • Multi-tenant   │                  │
│   │ • Full control   │    │ • Managed by us  │                  │
│   │ • BYOK           │    │ • Quick start    │                  │
│   │ • No data leaves │    │ • Subscription   │                  │
│   │ • Free forever   │    │ • Free tier      │                  │
│   └──────────────────┘    └──────────────────┘                  │
│            │                       │                             │
│            └───────────┬───────────┘                             │
│                        │                                         │
│              ┌─────────▼─────────┐                               │
│              │   SAME CODEBASE   │                               │
│              │   (with feature   │                               │
│              │    flags)         │                               │
│              └───────────────────┘                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Key Principle: One codebase that works for both models, with configuration/feature flags differentiating them.


2. Admin/Superuser Area Design

The Problem

Self-hosted admins need a privileged area to:

  • Start/stop services
  • View system logs
  • Configure system-wide API keys
  • Manage secrets
  • Monitor health
  • Configure integrations

This is fundamentally different from "organization admin" — it's instance admin.

Proposed: Instance Admin vs Org Admin Separation

┌─────────────────────────────────────────────────────────────────┐
│                    ADMIN HIERARCHY                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   INSTANCE ADMIN (Superuser)                                     │
│   ├── System Settings                                           │
│   │   ├── Service Management (start/stop/restart)               │
│   │   ├── System API Keys (Claude, OpenAI, etc.)                │
│   │   ├── Email/SMTP Configuration                              │
│   │   ├── SSO/OIDC Configuration                                │
│   │   ├── License Management                                     │
│   │   └── Backup/Restore                                         │
│   ├── Monitoring                                                 │
│   │   ├── Service Health Dashboard                              │
│   │   ├── System Logs Viewer                                    │
│   │   ├── Resource Usage (CPU, Memory, Disk)                    │
│   │   └── Active Sessions                                        │
│   ├── Security                                                   │
│   │   ├── Audit Log (instance-wide)                             │
│   │   ├── Rate Limit Configuration                              │
│   │   ├── IP Allowlisting                                        │
│   │   └── Security Policies                                      │
│   └── Organizations                                              │
│       ├── Create/Delete Organizations                            │
│       ├── Impersonate Users (for support)                        │
│       └── Organization Quotas                                    │
│                                                                  │
│   ORG ADMIN (Per-Organization)                                   │
│   ├── Members & Roles                                            │
│   ├── Teams                                                      │
│   ├── Org-Level Secrets                                          │
│   ├── Org Audit Log                                              │
│   └── Billing (if hosted)                                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Database Schema Addition

sql
-- Instance-level configuration (single row, key-value store)
CREATE TABLE instance_config (
    key TEXT PRIMARY KEY,
    value TEXT,
    encrypted INTEGER DEFAULT 0,
    updated_at TEXT DEFAULT (datetime('now')),
    updated_by TEXT
);

-- Instance admin users (separate from org roles)
CREATE TABLE instance_admins (
    id TEXT PRIMARY KEY,
    user_id TEXT NOT NULL REFERENCES users(id),
    role TEXT NOT NULL DEFAULT 'admin',  -- admin, readonly
    created_at TEXT DEFAULT (datetime('now')),
    created_by TEXT
);

-- System-level API keys
CREATE TABLE system_api_keys (
    id TEXT PRIMARY KEY,
    provider TEXT NOT NULL,  -- 'anthropic', 'openai', 'elevenlabs', etc.
    name TEXT NOT NULL,
    key_ciphertext TEXT NOT NULL,  -- Encrypted
    is_default INTEGER DEFAULT 0,
    usage_policy TEXT DEFAULT 'all',  -- 'all', 'org_admin_only', 'disabled'
    created_at TEXT DEFAULT (datetime('now')),
    updated_at TEXT
);

-- System logs (recent, rotated)
CREATE TABLE system_logs (
    id TEXT PRIMARY KEY,
    service TEXT NOT NULL,
    level TEXT NOT NULL,  -- error, warn, info, debug
    message TEXT NOT NULL,
    metadata_json TEXT,
    created_at TEXT DEFAULT (datetime('now'))
);

UI Access Pattern

URL Structure:
  /admin/*           → Instance Admin (requires instance_admin role)
  /settings/*        → Org Settings (requires org admin role)
  /dashboard/*       → Regular user dashboard

First User Flow:
  1. First user to sign up becomes instance admin
  2. Can create organizations
  3. Can designate other instance admins

3. API Key Management Strategy

The Core Question

i

Who controls which API keys? Can teams/users bring their own?

Option 1: System Keys Only (Restrictive)

Model: Instance admin configures all API keys. Users cannot add their own.

Instance Admin
    └── System API Keys (Anthropic, OpenAI, etc.)
        └── All orgs/users use these keys

Pros: Simple, centralized control, predictable costs Cons: No user flexibility, admin bottleneck

Use Case: Corporate deployments where IT controls all resources


Option 2: User Keys Only (BYOK-Only)

Model: No system keys. Every user must provide their own.

User
    └── Personal API Keys
        └── Used for their workflows

Pros: Zero cost for operator, full user autonomy Cons: Onboarding friction, no fallback, complex for teams

Use Case: Developer tools like JetBrains AI BYOK, VS Code BYOK


Model: Keys cascade from instance → org → team → user with configurable policies.

┌─────────────────────────────────────────────────────────────────┐
│                   KEY HIERARCHY                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│   INSTANCE LEVEL (Admin)                                         │
│   ├── System Default Keys (Anthropic, OpenAI, etc.)             │
│   ├── Policy: Allow org override? [yes/no]                      │
│   └── Policy: Allow user BYOK? [yes/no]                         │
│       │                                                          │
│       ▼                                                          │
│   ORG LEVEL (Org Admin)                                          │
│   ├── Org Keys (override system, if allowed)                    │
│   ├── Policy: Allow team override? [yes/no]                     │
│   └── Policy: Allow user BYOK? [yes/no]                         │
│       │                                                          │
│       ▼                                                          │
│   TEAM LEVEL (Team Admin)                                        │
│   ├── Team Keys (override org, if allowed)                      │
│   └── Policy: Allow user BYOK? [yes/no]                         │
│       │                                                          │
│       ▼                                                          │
│   USER LEVEL                                                     │
│   └── Personal Keys (BYOK, if allowed)                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Resolution Order:
  User Key → Team Key → Org Key → System Key → Error

Policy Configuration Examples

Corporate Lockdown:

json
{
  "instance_policy": {
    "allow_org_keys": false,
    "allow_user_byok": false,
    "require_approval_for_new_providers": true
  }
}

All users use system keys. No overrides allowed.

Startup Flexible:

json
{
  "instance_policy": {
    "allow_org_keys": true,
    "allow_user_byok": true,
    "default_to_system_keys": true
  }
}

System keys available by default, users can override with their own.

BYOK-Only (No Central Keys):

json
{
  "instance_policy": {
    "system_keys_enabled": false,
    "require_user_byok": true
  }
}

No system keys, users must provide their own.

Database Schema for Key Hierarchy

sql
-- Key policies at each level
CREATE TABLE key_policies (
    id TEXT PRIMARY KEY,
    scope_type TEXT NOT NULL,  -- 'instance', 'org', 'team', 'user'
    scope_id TEXT,             -- null for instance, org_id, team_id, user_id
    allow_override INTEGER DEFAULT 1,
    allow_byok INTEGER DEFAULT 1,
    allowed_providers TEXT,    -- JSON array: ['anthropic', 'openai']
    created_at TEXT,
    updated_at TEXT
);

-- API keys at any scope level
CREATE TABLE api_keys (
    id TEXT PRIMARY KEY,
    scope_type TEXT NOT NULL,  -- 'instance', 'org', 'team', 'user'
    scope_id TEXT,
    provider TEXT NOT NULL,    -- 'anthropic', 'openai', 'elevenlabs'
    name TEXT NOT NULL,
    key_ciphertext TEXT NOT NULL,
    key_preview TEXT,          -- Last 4 chars for identification
    is_active INTEGER DEFAULT 1,
    usage_count INTEGER DEFAULT 0,
    last_used_at TEXT,
    created_by TEXT REFERENCES users(id),
    created_at TEXT DEFAULT (datetime('now')),
    UNIQUE(scope_type, scope_id, provider, name)
);

Key Resolution Function

javascript
async function resolveApiKey(provider, context) {
    const { userId, teamId, orgId } = context;

    // 1. Check user key (if BYOK allowed)
    if (userId) {
        const userKey = await getKey('user', userId, provider);
        if (userKey && await isBYOKAllowed('user', userId)) {
            return userKey;
        }
    }

    // 2. Check team key (if override allowed)
    if (teamId) {
        const teamKey = await getKey('team', teamId, provider);
        if (teamKey && await isOverrideAllowed('team', teamId)) {
            return teamKey;
        }
    }

    // 3. Check org key (if override allowed)
    if (orgId) {
        const orgKey = await getKey('org', orgId, provider);
        if (orgKey && await isOverrideAllowed('org', orgId)) {
            return orgKey;
        }
    }

    // 4. Fall back to system key
    const systemKey = await getKey('instance', null, provider);
    if (systemKey) {
        return systemKey;
    }

    throw new Error(`No API key available for provider: ${provider}`);
}

4. Team Permission Models

Question: How much autonomy do teams have?

Model A: Centralized (Admin Controls Everything)

Instance Admin
    └── Creates all orgs, teams, users
        └── Assigns all roles
            └── Configures all keys

Pros: Full control, predictable Cons: Admin bottleneck, doesn't scale


Model B: Delegated (Admins Create Orgs, Org Admins Manage)

Instance Admin
    └── Creates orgs, assigns org owners
        └── Org Owner
            └── Creates teams, invites users
                └── Team Admin
                    └── Manages team members

Pros: Scales well, clear hierarchy Cons: Need clear policies on what each level can do


Any User
    └── Can create own org (rate limited)
        └── Becomes org owner
            └── Invites team members

Pros: Low friction, viral growth Cons: Abuse potential, resource management


The instance admin chooses which model to use:

json
{
  "user_permissions": {
    "can_create_org": true,        // Self-hosted: false, Hosted: true
    "max_orgs_per_user": 3,        // Limit for hosted
    "require_email_domain": null,  // Corporate: "company.com"
    "require_invite": false        // Closed beta: true
  }
}

5. Future Hosted Service Considerations

Architecture Decisions to Preserve Optionality

DecisionSelf-HostedHostedSolution
DatabaseSQLite (single file)PostgreSQL (managed)Abstract database layer
File StorageLocal filesystemS3/R2Storage interface
AuthLocal passwordsOAuth + localBoth supported
SecretsLocal encryptionKMSPluggable crypto
Multi-tenancySingle orgMany orgsAlways org-scoped
BillingNoneStripeFeature flag

Key Abstractions Needed

javascript
// Database abstraction
const db = process.env.DATABASE_URL?.startsWith('postgres')
    ? new PostgresAdapter(process.env.DATABASE_URL)
    : new SqliteAdapter(process.env.AUTH_DB_PATH);

// Storage abstraction
const storage = process.env.S3_BUCKET
    ? new S3Storage(config)
    : new LocalStorage(process.env.STORAGE_PATH);

// Secrets abstraction
const secrets = process.env.KMS_KEY_ID
    ? new KMSSecrets(config)
    : new LocalSecrets(process.env.MASTER_KEY);

Hosted-Specific Features (Behind Feature Flags)

javascript
const HOSTED_FEATURES = {
    billing: process.env.STRIPE_KEY !== undefined,
    usageMetering: process.env.HOSTED === 'true',
    automaticBackups: process.env.HOSTED === 'true',
    multiRegion: process.env.HOSTED === 'true',
    freeTrials: process.env.HOSTED === 'true'
};

6. Recommendations Summary

Deployment Model

✅ Hybrid: Self-hosted first, hosted option later

  • Open source core with all essential features
  • Hosted version uses same codebase
  • Enterprise features for monetization

Admin Area

✅ Separate Instance Admin from Org Admin

  • Instance Admin: System settings, logs, system keys
  • Org Admin: Members, teams, org settings
  • First user becomes instance admin

Key Management

✅ Hierarchical with configurable delegation

  • Instance → Org → Team → User cascade
  • Policies at each level control what's allowed
  • BYOK optional and configurable

Team Permissions

✅ Configurable self-service model

  • Default: Admins create orgs
  • Optional: Users can create orgs (hosted)
  • Rate limits and quotas for abuse prevention

Future Hosting

✅ Build abstractions now

  • Database layer (SQLite ↔ PostgreSQL)
  • Storage layer (Local ↔ S3)
  • Secrets layer (Local ↔ KMS)
  • Feature flags for hosted-specific features

7. Implementation Priority

Phase A (Complete)

  • User authentication
  • Organization management
  • Basic RBAC
  • Instance Admin separation
  • System API key management
  • Key policy configuration
  • Admin dashboard (logs, health)

Phase B (As Planned)

  • Organization hierarchy (divisions, departments, teams)
  • Key hierarchy implementation
  • Team-level key management

Phase C (As Planned)

  • Human-in-the-loop
  • Inbox and approvals

Phase D (As Planned)

  • Workflow builder

8. Decision Points Requiring Your Input

  1. Default Key Policy: Should new instances default to:

    • (a) System keys only (admin must configure)
    • (b) BYOK required (no system keys)
    • (c) Both available (configurable)
  2. Org Creation: Should users be able to create their own orgs, or admin-only?

  3. Instance Admin UI: Should this be:

    • (a) Integrated into main dashboard (with role check)
    • (b) Separate application/port
    • (c) CLI-only initially
  4. Hosted Service Timeline:

    • (a) Build abstractions now, launch hosted later
    • (b) Focus on self-hosted only for now
    • (c) Launch hosted MVP alongside self-hosted

Sources


Report generated: 2026-01-21