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
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
5.7 KiB
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
- No PII: Never collect personally identifiable information
- Anonymization: Configurable user ID anonymization via ANALYTICS_ANONYMIZE_USER_IDS
- Transparency: Show notice on first load
- 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
- Check if enabled:
import { PrivacyHelper } from '@/lib/analytics/privacy';
if (PrivacyHelper.shouldCollectTelemetry()) {
// Analytics is enabled
}
- 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
- 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
- Always sanitize data before sending to analytics
- Use consistent event names from AnalyticsEvents enum
- Include relevant context but avoid PII
- Track errors without exposing sensitive information
- Measure performance to identify bottlenecks
- Respect user privacy - when in doubt, don't track it
Troubleshooting
Analytics not working?
- Check environment variables are set correctly
- Verify ALGA_USAGE_STATS is not set to 'false'
- Check terminal output for the usage stats notice
- Check browser console for errors
- Verify network requests to PostHog
Events not showing up?
- PostHog batches events - wait 30 seconds
- Check if running in development mode
- Verify event names match what's in PostHog
- Check for sanitization removing all properties
Privacy concerns?
- Review what data is being sent in browser network tab
- Check PrivacyHelper.sanitizeProperties output
- Ensure no PII is included in event properties
- Set ALGA_USAGE_STATS=false to disable completely