Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

5.7 KiB

Analytics Integration Guide

This guide explains how to use the PostHog analytics integration in alga-psa.

Overview

The analytics system is designed to:

  • Collect anonymous usage statistics to improve the product
  • Respect user privacy with easy opt-out
  • Separate operational metrics (Grafana) from product analytics (PostHog)
  • Provide configurable privacy controls

Configuration

Environment Variables

# Enable/disable usage statistics
ALGA_USAGE_STATS=true  # Set to false to opt out

# Analytics anonymization
ANALYTICS_ANONYMIZE_USER_IDS=true  # Set to false to use actual user IDs
NEXT_PUBLIC_ANALYTICS_ANONYMIZE_USER_IDS=true  # Must match ANALYTICS_ANONYMIZE_USER_IDS

# Instance identification (optional)
INSTANCE_ID=my-company-instance

# Note: PostHog API key is configured in server/src/config/posthog.config.ts

Usage Examples

Server-Side Analytics

import { analytics } from '@/lib/analytics/posthog';
import { AnalyticsEvents } from '@/lib/analytics/events';

// Track a simple event
analytics.capture(AnalyticsEvents.TICKET_CREATED, {
  ticket_type: 'support',
  priority: 'high',
  has_attachments: true,
});

// Track with user context (when anonymization is disabled)
analytics.capture(AnalyticsEvents.USER_LOGGED_IN, {
  login_method: 'email',
  two_factor_enabled: true,
}, userId);

// Identify a user (when anonymization is disabled)
analytics.identify(userId, {
  plan: 'enterprise',
  company_size: 'medium',
  industry: 'technology',
});

Client-Side Analytics

import { usePostHog } from 'posthog-js/react';

export function MyComponent() {
  const posthog = usePostHog();
  
  const handleAction = () => {
    // Track client-side events
    posthog?.capture('button_clicked', {
      button_name: 'create_ticket',
      location: 'dashboard',
    });
  };
  
  return <button onClick={handleAction}>Create Ticket</button>;
}

API Route Example

// app/api/tickets/route.ts
import { analytics } from '@/lib/analytics/posthog';
import { AnalyticsEvents, createEventProperties } from '@/lib/analytics/events';

export async function POST(req: Request) {
  const startTime = Date.now();
  
  try {
    const data = await req.json();
    const ticket = await createTicket(data);
    
    // Track successful creation
    analytics.capture(AnalyticsEvents.TICKET_CREATED, createEventProperties({
      ticket_type: ticket.type,
      priority: ticket.priority,
      response_time: Date.now() - startTime,
      source: 'api',
    }));
    
    return Response.json(ticket);
  } catch (error) {
    // Track errors (without sensitive data)
    analytics.capture(AnalyticsEvents.API_ERROR, {
      endpoint: '/api/tickets',
      method: 'POST',
      error_type: error.name,
      response_time: Date.now() - startTime,
    });
    
    throw error;
  }
}

Privacy Considerations

Data Collection Principles

  1. No PII: Never collect personally identifiable information
  2. Anonymization: Configurable user ID anonymization via ANALYTICS_ANONYMIZE_USER_IDS
  3. Transparency: Show notice on first load
  4. User Control: Easy opt-out via environment variable

What We Collect

When Anonymization is Disabled (ANALYTICS_ANONYMIZE_USER_IDS=false):

  • Feature usage with user context
  • Performance metrics per user
  • Error patterns with user association
  • User journeys

When Anonymization is Enabled (ANALYTICS_ANONYMIZE_USER_IDS=true):

  • Anonymous feature usage
  • Aggregate performance data
  • Error types (no user association)
  • Version information

What We Don't Collect

  • Names, emails, or other PII
  • Customer data
  • Sensitive business information
  • IP addresses (anonymized)
  • Detailed error messages

Testing Analytics

  1. Check if enabled:
import { PrivacyHelper } from '@/lib/analytics/privacy';

if (PrivacyHelper.shouldCollectTelemetry()) {
  // Analytics is enabled
}
  1. Test event capture:
# Set environment variable
export ALGA_USAGE_STATS=true

# Run your application and check console logs
# You should see: "Usage statistics enabled (user IDs anonymized)" or "Usage statistics enabled (user IDs preserved)"
# Plus a notice box on first run
  1. Test opt-out:
# Set environment variable
export ALGA_USAGE_STATS=false

# Run your application and check console logs
# You should see: "Usage statistics disabled by ALGA_USAGE_STATS=false"

Common Events to Track

  • User authentication (login/logout/signup)
  • Feature usage (which features are used most)
  • Performance metrics (slow queries, API response times)
  • Errors (types and frequency, not details)
  • User journeys (how users navigate the app)
  • Search patterns (what users search for)
  • Export/report generation

Best Practices

  1. Always sanitize data before sending to analytics
  2. Use consistent event names from AnalyticsEvents enum
  3. Include relevant context but avoid PII
  4. Track errors without exposing sensitive information
  5. Measure performance to identify bottlenecks
  6. Respect user privacy - when in doubt, don't track it

Troubleshooting

Analytics not working?

  1. Check environment variables are set correctly
  2. Verify ALGA_USAGE_STATS is not set to 'false'
  3. Check terminal output for the usage stats notice
  4. Check browser console for errors
  5. Verify network requests to PostHog

Events not showing up?

  1. PostHog batches events - wait 30 seconds
  2. Check if running in development mode
  3. Verify event names match what's in PostHog
  4. Check for sanitization removing all properties

Privacy concerns?

  1. Review what data is being sent in browser network tab
  2. Check PrivacyHelper.sanitizeProperties output
  3. Ensure no PII is included in event properties
  4. Set ALGA_USAGE_STATS=false to disable completely