MixPanel analytics tracking implementation and review Skill for Django4Lyfe optimo_analytics module. Implements new events following established patterns and reviews implementations for PII protection, schema design, and code quality.
MixPanel analytics tracking implementation and review Skill for Django4Lyfe optimo_analytics module. Implements new events following established patterns and reviews implementations for PII protection, schema design, and code quality.
# Event naming convention: {prefix}.{object}.{action}[.error]# Examples:# - svc.surveys.survey_delivered# - svc.map.action_plan_created# - svc.hris_csv.upload.analysis_completed## NOTE: Do NOT include "cron" in event names - use is_cron_job property insteadclassMixPanelEvent:
# Add under appropriate section with comment
NEW_EVENT_NAME = "svc.domain.action_name"
# Schema naming: Mxp{Domain}{Action}EventSchema# CRITICAL RULES:# - All UUIDs MUST be strings (str, not UUID)# - NO PII: no names, emails, phone numbers# - organization_name IS allowed (business approved)# - Use STRICT_MODEL_CONFIG (no aliases) or ALIASED_MODEL_CONFIG ($ aliases)classMxpNewEventSchema(MixpanelSuperEventPropertiesSchema):
"""Properties for svc.domain.action_name event.
Tracked when [describe when this event fires].
"""# Required fields (no defaults)
employee_id: str = Field(description="Employee UUID as string")
organization_id: str = Field(description="Organization UUID as string")
organization_name: str = Field(description="Organization name for analytics")
role: SystemRole | None = Field(description="User role")
impersonation: bool = Field(description="Is impersonated session")
# Event-specific fields
custom_field: str = Field(description="What this field represents")
# Use STRICT_MODEL_CONFIG for internal-only schemas# Use ALIASED_MODEL_CONFIG when field names need $ prefix for MixPanel (e.g., $device_id)
model_config = STRICT_MODEL_CONFIG
Step 3: Register in Registry (optimo_analytics/registry.py)
classMxpNewEventSchema(MixpanelSuperEventPropertiesSchema):
# Inherit organization_id, organization_name from base schema# Pass empty string when value is not availablepass# In service method:
properties = MxpNewEventSchema(
organization_id=str(org.uuid) if org else"",
organization_name=org.name if org else"",
# ...
)
## Post-Implementation Validations
```bash
# 1. Ruff lint and format
.bin/ruff check optimo_analytics/ --fix
.bin/ruff format optimo_analytics/
# 2. Type checking
.bin/ty check optimo_analytics/
# 3. Django checks
DJANGO_CONFIGURATION=DevApp uv run python manage.py check
# 4. Run tests
.bin/pytest optimo_analytics/tests/ -v --dc=TestLocalApp
Review Mode
Review Checklist
1. PII Protection (CRITICAL - P0)
MUST CHECK:
No first_name, last_name, full_name, display_name in schemas
No email, email_address, user_email fields
No phone, phone_number, phone_e164 fields
No address, city, country as free-text fields
All identifiers are UUIDs as strings (not UUID objects)
organization_name is ONLY sent to MixPanel, never logged
2. Event Registration Completeness (P1)
MUST VERIFY:
Event constant exists in constants.py under MixPanelEvent
Schema class exists in schemas.py
Event is registered in registry.py_EVENT_SCHEMA_REGISTRY
Schema inherits from MixpanelSuperEventPropertiesSchema
3. Schema Design (P1)
MUST VERIFY:
All UUID fields are typed as str, not UUID
All required fields have Field(description="...")
Uses STRICT_MODEL_CONFIG or ALIASED_MODEL_CONFIG appropriately
Enum fields use SystemRole | None pattern
Docstring describes when the event is tracked
Base schema fields from MixpanelSuperEventPropertiesSchema are NOT
redefined as Optional[str] - pass empty string "" for missing values