Actors

An actor in CONA represents any entity that can perform actions within an organization. Actors provide a unified way to track and attribute actions across the system.

Types of Actors

User Actors

  • Purpose: Represent a person within an organization
  • Creation: Created when a user joins an organization
  • Identification: Has user_id populated, uses label field
  • Usage: Authentication, permissions, user actions
  • Example: actor_123 with user_id: "user_456" and label: "John Doe"

App Actors

  • Purpose: Represent an app/integration within an organization
  • Creation: Created when an app is installed
  • Identification: Has user_id as null, uses apps_label field
  • Usage: System actions, automated processes, app-generated data
  • Example: actor_789 with user_id: null and apps_label: "shopify"

Database Structure

-- Actors table (from actual schema)
model actors {
    id                String       @id @default(cuid())
    user_id           String?      -- Links to users table (for user actors only)
    label             String       -- Used for user actors
    apps_label        String?      -- Used for app actors  
    org_id            String       -- Organization context
    avatar_url        String?      -- For user actors
    logo_url          String?      -- For app actors
    -- ... other fields
    
    @@unique([apps_label, org_id])
    @@unique([label, org_id])
    @@unique([user_id, org_id])
}

Key Distinctions

User Actors:

  • user_id is populated
  • Uses label field for name
  • Has avatar_url for profile picture
  • Unique constraint on [user_id, org_id] and [label, org_id]

App Actors:

  • user_id is null
  • Uses apps_label field for app identifier
  • Has logo_url for app logo
  • Unique constraint on [apps_label, org_id]

Important Distinction for Analytics

When tracking user actions in PostHog, always use the authenticated user’s actor ID:

// ✅ Correct - track user action
const { actorId: userActorId } = await requireAuth();
await trackEventWithAuth(userActorId, organizationId, organizationName, "action_performed", {});

// ❌ Wrong - using app actor from data
const appInstallation = { actor_id: "app_actor_123" }; // This could be an app actor!
await trackEventWithAuth(appInstallation.actor_id, ...); // This would attribute action to the app!

Key Takeaway

  • User actors: Have user_id populated, for tracking human actions and analytics
  • App actors: Have user_id as null, for system/automated actions and data attribution
  • Always verify: Check if user_id is populated to determine actor type when tracking events