Overview

The App model represents third-party applications (TPAs) in the MentraOS ecosystem. It stores app metadata, authentication credentials, webhook configurations, and app store status.

Location

packages/cloud/src/models/app.model.ts

Schema Structure

Core Fields

{
  // Identity
  packageName: string,              // Unique identifier (e.g., "com.translator.app")
  name: string,                     // Display name
  description: string,              // App description
  version: string,                  // Semantic version
  type: AppType,                    // 'AGENT' | 'UI' | 'HARDWARE'
  
  // Authentication
  hashedApiKey: string,             // Hashed API key for authentication
  hashedEndpointSecret?: string,    // Optional webhook secret
  
  // Store Management
  appStoreStatus: AppStoreStatus,   // Development/Published status
  isPublic: boolean,                // Publicly available flag
  reviewNotes?: string,             // Review process notes
  reviewedBy?: string,              // Reviewer identifier
  reviewedAt?: Date,                // Review timestamp
  
  // Organization
  organizationId?: ObjectId,        // Owning organization
  
  // Configuration
  settings?: AppSetting[],          // Available settings
  permissions?: Permission[],       // Required permissions
  tools?: ToolSchema[],            // AI tool definitions
  webhooks?: WebhookConfig,        // Webhook endpoints
  hardware?: HardwareRequirement[], // Hardware requirements
  
  // Metadata
  logo?: string,                    // App logo URL
  smallLogo?: string,              // Small logo variant
  bannerImage?: string,            // Store banner image
  screenshots?: string[],          // App screenshots
  demoVideoUrl?: string,           // Demo video
  supportUrl?: string,             // Support contact
  documentationUrl?: string,       // Documentation link
  websiteUrl?: string,             // Marketing website
  privacyPolicyUrl?: string,       // Privacy policy
  termsOfServiceUrl?: string,      // Terms of service
  
  // Analytics
  installCount?: number,           // Total installations
  activeUsers?: number,            // Active user count
  rating?: number,                 // Average rating
  featured?: boolean,              // Featured app flag
  
  // Timestamps
  createdAt: Date,
  updatedAt: Date
}

App Types

enum AppType {
  AGENT = 'AGENT',      // AI-powered apps
  UI = 'UI',           // Visual interface apps
  HARDWARE = 'HARDWARE' // Hardware integration apps
}

App Store Status

type AppStoreStatus = 
  | 'DEVELOPMENT'    // In development, not public
  | 'SUBMITTED'      // Submitted for review
  | 'REJECTED'       // Failed review
  | 'PUBLISHED'      // Available in store

Settings Configuration

Apps can define user-configurable settings:
settings: [{
  key: string,                    // Setting identifier
  type: AppSettingType,          // STRING | NUMBER | BOOLEAN | SELECT
  label: string,                 // Display label
  description?: string,          // Help text
  defaultValue?: any,           // Default value
  required?: boolean,           // Required flag
  options?: Array<{             // For SELECT type
    label: string,
    value: string
  }>,
  min?: number,                 // For NUMBER type
  max?: number,
  step?: number
}]

Permission Declarations

Apps must declare required permissions:
permissions: [{
  type: PermissionType,         // Permission category
  reason: string,               // Why it's needed
  required: boolean,            // Required vs optional
  settings?: any               // Permission-specific config
}]
Permission types include:
  • TRANSCRIPTION: Access to speech-to-text
  • AUDIO: Access to audio stream
  • CAMERA: Camera/photo access
  • LOCATION: Location data
  • NOTIFICATIONS: Phone notifications
  • DISPLAY: Screen output
  • STORAGE: Persistent storage

Hardware Requirements

Apps can specify hardware needs:
hardware: [{
  type: HardwareType,                    // DISPLAY | CAMERA | etc.
  level: HardwareRequirementLevel,       // REQUIRED | OPTIONAL
  minVersion?: string,                   // Minimum version
  features?: string[]                    // Specific features
}]

Webhook Configuration

webhooks: {
  start?: {
    url: string,                        // Webhook URL
    headers?: Record<string, string>,   // Custom headers
    timeout?: number                    // Timeout in ms
  },
  stop?: { /* same structure */ },
  toolCall?: { /* same structure */ }
}

Tool Schemas

For AI-powered apps:
tools: [{
  name: string,                         // Tool identifier
  description: string,                  // What it does
  inputSchema: {                        // JSON Schema
    type: 'object',
    properties: { /* ... */ },
    required: string[]
  },
  outputSchema?: { /* ... */ }          // Expected output
}]

Indexes

  • packageName: Unique index
  • organizationId: For org queries
  • appStoreStatus: For store filtering
  • type: For category queries
  • featured: For featured apps

Methods

Instance Methods

The App model primarily uses standard Mongoose methods:
// Find app
const app = await App.findOne({ packageName: 'com.translator.app' });

// Update app
app.version = '1.2.0';
await app.save();

// Soft delete
app.isPublic = false;
app.appStoreStatus = 'DEVELOPMENT';
await app.save();

Static Methods

// Find all published apps
const publishedApps = await App.find({ 
  appStoreStatus: 'PUBLISHED',
  isPublic: true 
});

// Find organization apps
const orgApps = await App.find({ 
  organizationId: orgId 
});

Security

API Key Management

  • API keys are hashed using SHA-256
  • Never store or transmit plain text keys
  • Keys are generated using crypto-random

Webhook Security

  • Optional endpoint secrets for verification
  • HMAC signatures for webhook payloads
  • Timeout limits to prevent hanging

App Lifecycle

Development Flow

  1. DEVELOPMENT: App created, private to developer
  2. SUBMITTED: Submitted for review
  3. REJECTED: Failed review (with notes)
  4. PUBLISHED: Available in public store

Review Process

// Submit for review
app.appStoreStatus = 'SUBMITTED';
app.reviewNotes = 'Ready for review';
await app.save();

// Review decision
app.appStoreStatus = 'PUBLISHED';
app.reviewedBy = 'reviewer@mentraos.com';
app.reviewedAt = new Date();
await app.save();

Best Practices

  1. Validate package names - Use reverse domain notation
  2. Version semantically - Follow semver (1.0.0)
  3. Declare all permissions - Be transparent
  4. Provide documentation - Help users understand
  5. Test webhooks - Ensure they’re responsive
  6. Handle errors gracefully - Don’t crash user sessions

Example Usage

Creating an App

const app = new App({
  packageName: 'com.example.translator',
  name: 'Universal Translator',
  description: 'Real-time translation for smart glasses',
  version: '1.0.0',
  type: 'UI',
  
  // Organization
  organizationId: orgId,
  
  // Settings
  settings: [
    {
      key: 'targetLanguage',
      type: 'SELECT',
      label: 'Target Language',
      defaultValue: 'es',
      options: [
        { label: 'Spanish', value: 'es' },
        { label: 'French', value: 'fr' }
      ]
    }
  ],
  
  // Permissions
  permissions: [
    {
      type: 'TRANSCRIPTION',
      reason: 'To capture speech for translation',
      required: true
    },
    {
      type: 'DISPLAY',
      reason: 'To show translations',
      required: true
    }
  ],
  
  // Webhooks
  webhooks: {
    start: {
      url: 'https://api.example.com/webhook/start',
      headers: { 'X-API-Key': 'webhook-key' }
    }
  },
  
  // Store info
  appStoreStatus: 'DEVELOPMENT',
  isPublic: false,
  logo: 'https://example.com/logo.png',
  supportUrl: 'support@example.com'
});

// Hash the API key before saving
app.hashedApiKey = hashApiKey('app_secret_key');
await app.save();

Finding Apps for User

// Get user's installed apps
const user = await User.findOne({ email: 'user@example.com' });
const installedPackageNames = user.installedApps.map(a => a.packageName);

// Find app details
const apps = await App.find({
  packageName: { $in: installedPackageNames },
  appStoreStatus: 'PUBLISHED'
}).lean();