vybekiit 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +22134 -4
- package/dist/global-skills/add-ai/SKILL.md +53 -0
- package/dist/global-skills/add-analytics/SKILL.md +65 -0
- package/dist/global-skills/add-app-clip/SKILL.md +280 -0
- package/dist/global-skills/add-app-clip/agents/openai.yaml +4 -0
- package/dist/global-skills/add-app-clip/references/native-module.md +96 -0
- package/dist/global-skills/add-blog/SKILL.md +49 -0
- package/dist/global-skills/add-crud/SKILL.md +28 -0
- package/dist/global-skills/add-files/SKILL.md +65 -0
- package/dist/global-skills/add-images/SKILL.md +64 -0
- package/dist/global-skills/add-language/SKILL.md +44 -0
- package/dist/global-skills/add-notifications/SKILL.md +61 -0
- package/dist/global-skills/add-realtime/SKILL.md +49 -0
- package/dist/global-skills/add-route/SKILL.md +28 -0
- package/dist/global-skills/add-search/SKILL.md +43 -0
- package/dist/global-skills/add-signin/SKILL.md +78 -0
- package/dist/global-skills/add-teams/SKILL.md +64 -0
- package/dist/global-skills/add-upload/SKILL.md +27 -0
- package/dist/global-skills/aws-cdk/SKILL.md +72 -0
- package/dist/global-skills/aws-cdk/references/bootstrap-and-project-setup.md +257 -0
- package/dist/global-skills/aws-cdk/references/compliance-and-drift.md +193 -0
- package/dist/global-skills/aws-cdk/references/construct-patterns.md +315 -0
- package/dist/global-skills/aws-cdk/references/import-and-migrate.md +184 -0
- package/dist/global-skills/aws-cdk/references/refactor-and-prevent-replacement.md +198 -0
- package/dist/global-skills/aws-cdk/references/troubleshooting-credentials.md +183 -0
- package/dist/global-skills/aws-cdk/references/troubleshooting-deployment.md +293 -0
- package/dist/global-skills/aws-cdk/references/troubleshooting-synth.md +274 -0
- package/dist/global-skills/aws-cdk/references/v1-to-v2-migration.md +119 -0
- package/dist/global-skills/aws-cloudformation/SKILL.md +88 -0
- package/dist/global-skills/aws-cloudformation/references/author-cloudformation-best-practices.script.md +179 -0
- package/dist/global-skills/aws-cloudformation/references/check-cloudformation-template-compliance.script.md +159 -0
- package/dist/global-skills/aws-cloudformation/references/cloudformation-pre-deploy-validation.script.md +217 -0
- package/dist/global-skills/aws-cloudformation/references/deploy-with-express-mode.script.md +271 -0
- package/dist/global-skills/aws-cloudformation/references/lookup-resource-properties.script.md +130 -0
- package/dist/global-skills/aws-cloudformation/references/troubleshoot-deployment.script.md +200 -0
- package/dist/global-skills/aws-cloudformation/references/validate-cloudformation-template.script.md +135 -0
- package/dist/global-skills/aws-serverless/SKILL.md +51 -0
- package/dist/global-skills/aws-serverless/assets/powertools-handler.py +49 -0
- package/dist/global-skills/aws-serverless/references/api-gateway.md +553 -0
- package/dist/global-skills/aws-serverless/references/architecture.md +262 -0
- package/dist/global-skills/aws-serverless/references/concurrency.md +200 -0
- package/dist/global-skills/aws-serverless/references/deployment.md +94 -0
- package/dist/global-skills/aws-serverless/references/event-sources.md +484 -0
- package/dist/global-skills/aws-serverless/references/lambda.md +548 -0
- package/dist/global-skills/aws-serverless/references/orchestration.md +449 -0
- package/dist/global-skills/aws-serverless/references/production.md +493 -0
- package/dist/global-skills/aws-serverless/references/troubleshooting.md +711 -0
- package/dist/global-skills/back-up-my-code/SKILL.md +48 -0
- package/dist/global-skills/better-auth-best-practices/SKILL.md +182 -0
- package/dist/global-skills/better-auth-security-best-practices/SKILL.md +432 -0
- package/dist/global-skills/building-native-ui/SKILL.md +377 -0
- package/dist/global-skills/building-native-ui/agents/openai.yaml +4 -0
- package/dist/global-skills/building-native-ui/references/animations.md +220 -0
- package/dist/global-skills/building-native-ui/references/controls.md +270 -0
- package/dist/global-skills/building-native-ui/references/form-sheet.md +253 -0
- package/dist/global-skills/building-native-ui/references/gradients.md +106 -0
- package/dist/global-skills/building-native-ui/references/icons.md +213 -0
- package/dist/global-skills/building-native-ui/references/media.md +198 -0
- package/dist/global-skills/building-native-ui/references/route-structure.md +229 -0
- package/dist/global-skills/building-native-ui/references/search.md +248 -0
- package/dist/global-skills/building-native-ui/references/storage.md +121 -0
- package/dist/global-skills/building-native-ui/references/tabs.md +433 -0
- package/dist/global-skills/building-native-ui/references/toolbar-and-headers.md +284 -0
- package/dist/global-skills/building-native-ui/references/visual-effects.md +197 -0
- package/dist/global-skills/building-native-ui/references/webgpu-three.md +605 -0
- package/dist/global-skills/building-native-ui/references/zoom-transitions.md +158 -0
- package/dist/global-skills/buy-domain/SKILL.md +64 -0
- package/dist/global-skills/check-safety/SKILL.md +94 -0
- package/dist/global-skills/claimable-postgres/SKILL.md +249 -0
- package/dist/global-skills/configure-capabilities/SKILL.md +38 -0
- package/dist/global-skills/connect-account/SKILL.md +64 -0
- package/dist/global-skills/connect-account-backend/SKILL.md +41 -0
- package/dist/global-skills/create-auth-skill/SKILL.md +321 -0
- package/dist/global-skills/design-my-data/SKILL.md +48 -0
- package/dist/global-skills/doctor/SKILL.md +84 -0
- package/dist/global-skills/eas-app-stores/SKILL.md +152 -0
- package/dist/global-skills/eas-app-stores/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-app-stores/references/app-store-metadata.md +497 -0
- package/dist/global-skills/eas-app-stores/references/ios-app-store.md +371 -0
- package/dist/global-skills/eas-app-stores/references/play-store.md +246 -0
- package/dist/global-skills/eas-app-stores/references/testflight.md +58 -0
- package/dist/global-skills/eas-app-stores/references/workflows.md +120 -0
- package/dist/global-skills/eas-hosting/SKILL.md +423 -0
- package/dist/global-skills/eas-hosting/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-observe/SKILL.md +32 -0
- package/dist/global-skills/eas-observe/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-observe/references/metrics.md +47 -0
- package/dist/global-skills/eas-observe/references/queries.md +342 -0
- package/dist/global-skills/eas-observe/references/setup.md +317 -0
- package/dist/global-skills/eas-simulator/SKILL.md +156 -0
- package/dist/global-skills/eas-simulator/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-simulator/references/controllers.md +67 -0
- package/dist/global-skills/eas-simulator/references/run-your-app.md +185 -0
- package/dist/global-skills/eas-simulator/references/troubleshooting.md +38 -0
- package/dist/global-skills/eas-update-insights/SKILL.md +230 -0
- package/dist/global-skills/eas-update-insights/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-update-insights/references/channel-insights-schema.md +47 -0
- package/dist/global-skills/eas-update-insights/references/update-insights-schema.md +69 -0
- package/dist/global-skills/eas-workflows/SKILL.md +94 -0
- package/dist/global-skills/eas-workflows/agents/openai.yaml +4 -0
- package/dist/global-skills/eas-workflows/scripts/fetch.js +109 -0
- package/dist/global-skills/eas-workflows/scripts/package.json +11 -0
- package/dist/global-skills/eas-workflows/scripts/validate.js +84 -0
- package/dist/global-skills/email-best-practices/SKILL.md +73 -0
- package/dist/global-skills/expo-api-routes/SKILL.md +368 -0
- package/dist/global-skills/expo-api-routes/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-app-clip/SKILL.md +282 -0
- package/dist/global-skills/expo-app-clip/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-app-clip/references/native-module.md +96 -0
- package/dist/global-skills/expo-brownfield/SKILL.md +54 -0
- package/dist/global-skills/expo-brownfield/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-brownfield/references/brownfield-integrated.md +526 -0
- package/dist/global-skills/expo-brownfield/references/brownfield-isolated.md +402 -0
- package/dist/global-skills/expo-brownfield/references/comparison.md +63 -0
- package/dist/global-skills/expo-brownfield/references/troubleshooting.md +88 -0
- package/dist/global-skills/expo-cicd-workflows/SKILL.md +92 -0
- package/dist/global-skills/expo-cicd-workflows/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-cicd-workflows/scripts/fetch.js +109 -0
- package/dist/global-skills/expo-cicd-workflows/scripts/package.json +11 -0
- package/dist/global-skills/expo-cicd-workflows/scripts/validate.js +84 -0
- package/dist/global-skills/expo-data-fetching/SKILL.md +449 -0
- package/dist/global-skills/expo-data-fetching/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-data-fetching/references/expo-router-loaders.md +341 -0
- package/dist/global-skills/expo-data-fetching/references/offline-and-cancellation.md +68 -0
- package/dist/global-skills/expo-deployment/SKILL.md +167 -0
- package/dist/global-skills/expo-deployment/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-deployment/references/app-store-metadata.md +497 -0
- package/dist/global-skills/expo-deployment/references/ios-app-store.md +371 -0
- package/dist/global-skills/expo-deployment/references/play-store.md +246 -0
- package/dist/global-skills/expo-deployment/references/testflight.md +58 -0
- package/dist/global-skills/expo-deployment/references/workflows.md +160 -0
- package/dist/global-skills/expo-dev-client/SKILL.md +174 -0
- package/dist/global-skills/expo-dev-client/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-dom/SKILL.md +417 -0
- package/dist/global-skills/expo-dom/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-examples/SKILL.md +99 -0
- package/dist/global-skills/expo-examples/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-examples/references/catalog.md +105 -0
- package/dist/global-skills/expo-module/SKILL.md +141 -0
- package/dist/global-skills/expo-module/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-module/references/config-plugin.md +90 -0
- package/dist/global-skills/expo-module/references/create-expo-module.md +206 -0
- package/dist/global-skills/expo-module/references/lifecycle.md +127 -0
- package/dist/global-skills/expo-module/references/module-config.md +48 -0
- package/dist/global-skills/expo-module/references/native-module.md +286 -0
- package/dist/global-skills/expo-module/references/native-view.md +171 -0
- package/dist/global-skills/expo-native-ui/SKILL.md +181 -0
- package/dist/global-skills/expo-native-ui/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-native-ui/references/animations.md +220 -0
- package/dist/global-skills/expo-native-ui/references/controls.md +270 -0
- package/dist/global-skills/expo-native-ui/references/gradients.md +106 -0
- package/dist/global-skills/expo-native-ui/references/icons.md +213 -0
- package/dist/global-skills/expo-native-ui/references/media.md +198 -0
- package/dist/global-skills/expo-native-ui/references/storage.md +121 -0
- package/dist/global-skills/expo-native-ui/references/visual-effects.md +197 -0
- package/dist/global-skills/expo-native-ui/references/webgpu-three.md +605 -0
- package/dist/global-skills/expo-observe/SKILL.md +30 -0
- package/dist/global-skills/expo-observe/references/metrics.md +47 -0
- package/dist/global-skills/expo-observe/references/queries.md +342 -0
- package/dist/global-skills/expo-observe/references/setup.md +317 -0
- package/dist/global-skills/expo-router/SKILL.md +230 -0
- package/dist/global-skills/expo-router/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-router/references/form-sheet.md +253 -0
- package/dist/global-skills/expo-router/references/route-structure.md +229 -0
- package/dist/global-skills/expo-router/references/search.md +248 -0
- package/dist/global-skills/expo-router/references/tabs.md +433 -0
- package/dist/global-skills/expo-router/references/toolbar-and-headers.md +284 -0
- package/dist/global-skills/expo-router/references/zoom-transitions.md +158 -0
- package/dist/global-skills/expo-skill-eval/SKILL.md +314 -0
- package/dist/global-skills/expo-skill-eval/agents/visual-grader.md +52 -0
- package/dist/global-skills/expo-skill-eval/references/design-rubric.md +45 -0
- package/dist/global-skills/expo-skill-eval/references/runtime-matrix.md +34 -0
- package/dist/global-skills/expo-skill-eval/scripts/check-static.sh +64 -0
- package/dist/global-skills/expo-skill-eval/scripts/clean-fixture.sh +56 -0
- package/dist/global-skills/expo-skill-eval/scripts/generate_viewer.py +450 -0
- package/dist/global-skills/expo-skill-eval/scripts/latest-sdk.sh +46 -0
- package/dist/global-skills/expo-skill-eval/scripts/make-fixture.sh +95 -0
- package/dist/global-skills/expo-skill-eval/scripts/make-workspace.sh +31 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-android.sh +284 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-ios.sh +132 -0
- package/dist/global-skills/expo-skill-eval/scripts/snapshot-web.sh +61 -0
- package/dist/global-skills/expo-skill-feedback/SKILL.md +54 -0
- package/dist/global-skills/expo-skill-feedback/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-skill-feedback/scripts/skill-event.cjs +180 -0
- package/dist/global-skills/expo-skill-feedback/scripts/skill-feedback.cjs +118 -0
- package/dist/global-skills/expo-skill-feedback/scripts/telemetry.cjs +65 -0
- package/dist/global-skills/expo-skill-feedback/scripts/telemetry_common.cjs +171 -0
- package/dist/global-skills/expo-tailwind-setup/SKILL.md +480 -0
- package/dist/global-skills/expo-tailwind-setup/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-ui/SKILL.md +47 -0
- package/dist/global-skills/expo-ui/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-ui/references/drop-in-replacements.md +27 -0
- package/dist/global-skills/expo-ui/references/jetpack-compose.md +73 -0
- package/dist/global-skills/expo-ui/references/swift-ui.md +73 -0
- package/dist/global-skills/expo-ui/references/universal.md +73 -0
- package/dist/global-skills/expo-ui/scripts/list-components.js +193 -0
- package/dist/global-skills/expo-upgrade/SKILL.md +134 -0
- package/dist/global-skills/expo-upgrade/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-upgrade/references/expo-av-to-audio.md +132 -0
- package/dist/global-skills/expo-upgrade/references/expo-av-to-video.md +160 -0
- package/dist/global-skills/expo-upgrade/references/native-tabs.md +124 -0
- package/dist/global-skills/expo-upgrade/references/new-architecture.md +79 -0
- package/dist/global-skills/expo-upgrade/references/react-19.md +79 -0
- package/dist/global-skills/expo-upgrade/references/react-compiler.md +59 -0
- package/dist/global-skills/expo-upgrade/references/react-navigation-to-expo-router.md +61 -0
- package/dist/global-skills/expo-web-to-native/SKILL.md +83 -0
- package/dist/global-skills/expo-web-to-native/agents/openai.yaml +4 -0
- package/dist/global-skills/expo-web-to-native/references/false-friends.md +119 -0
- package/dist/global-skills/expo-web-to-native/references/native-patterns.md +39 -0
- package/dist/global-skills/expo-web-to-native/references/run-as-goal.md +48 -0
- package/dist/global-skills/expo-web-to-native/references/verify-on-device.md +45 -0
- package/dist/global-skills/firebase-ai-logic-basics/SKILL.md +165 -0
- package/dist/global-skills/firebase-ai-logic-basics/references/flutter_setup.md +95 -0
- package/dist/global-skills/firebase-ai-logic-basics/references/ios_setup.md +156 -0
- package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_android.md +157 -0
- package/dist/global-skills/firebase-ai-logic-basics/references/usage_patterns_web.md +186 -0
- package/dist/global-skills/firebase-app-hosting-basics/SKILL.md +73 -0
- package/dist/global-skills/firebase-app-hosting-basics/references/cli_commands.md +85 -0
- package/dist/global-skills/firebase-app-hosting-basics/references/configuration.md +59 -0
- package/dist/global-skills/firebase-app-hosting-basics/references/emulation.md +59 -0
- package/dist/global-skills/firebase-auth-basics/SKILL.md +118 -0
- package/dist/global-skills/firebase-auth-basics/references/client_sdk_android.md +160 -0
- package/dist/global-skills/firebase-auth-basics/references/client_sdk_web.md +301 -0
- package/dist/global-skills/firebase-auth-basics/references/flutter_setup.md +149 -0
- package/dist/global-skills/firebase-auth-basics/references/ios_setup.md +87 -0
- package/dist/global-skills/firebase-auth-basics/references/security_rules.md +49 -0
- package/dist/global-skills/firebase-basics/SKILL.md +148 -0
- package/dist/global-skills/firebase-basics/references/android_setup.md +41 -0
- package/dist/global-skills/firebase-basics/references/firebase-cli-guide.md +18 -0
- package/dist/global-skills/firebase-basics/references/firebase-service-init.md +20 -0
- package/dist/global-skills/firebase-basics/references/flutter_setup.md +143 -0
- package/dist/global-skills/firebase-basics/references/ios_setup.md +113 -0
- package/dist/global-skills/firebase-basics/references/local-env-setup.md +80 -0
- package/dist/global-skills/firebase-basics/references/refresh/android_studio.md +41 -0
- package/dist/global-skills/firebase-basics/references/refresh/antigravity.md +64 -0
- package/dist/global-skills/firebase-basics/references/refresh/claude.md +12 -0
- package/dist/global-skills/firebase-basics/references/refresh/gemini-cli.md +13 -0
- package/dist/global-skills/firebase-basics/references/refresh/other-agents.md +67 -0
- package/dist/global-skills/firebase-basics/references/setup/android_studio.md +23 -0
- package/dist/global-skills/firebase-basics/references/setup/antigravity.md +98 -0
- package/dist/global-skills/firebase-basics/references/setup/claude_code.md +45 -0
- package/dist/global-skills/firebase-basics/references/setup/cursor.md +93 -0
- package/dist/global-skills/firebase-basics/references/setup/gemini_cli.md +53 -0
- package/dist/global-skills/firebase-basics/references/setup/github_copilot.md +104 -0
- package/dist/global-skills/firebase-basics/references/setup/other_agents.md +99 -0
- package/dist/global-skills/firebase-basics/references/web_setup.md +77 -0
- package/dist/global-skills/firebase-crashlytics/SKILL.md +42 -0
- package/dist/global-skills/firebase-crashlytics/references/android_setup.md +152 -0
- package/dist/global-skills/firebase-crashlytics/references/ios_setup.md +115 -0
- package/dist/global-skills/firebase-data-connect/SKILL.md +191 -0
- package/dist/global-skills/firebase-data-connect/examples.md +638 -0
- package/dist/global-skills/firebase-data-connect/reference/cloud_functions.md +184 -0
- package/dist/global-skills/firebase-data-connect/reference/config.md +271 -0
- package/dist/global-skills/firebase-data-connect/reference/data_seeding.md +185 -0
- package/dist/global-skills/firebase-data-connect/reference/native_sql.md +170 -0
- package/dist/global-skills/firebase-data-connect/reference/operations.md +385 -0
- package/dist/global-skills/firebase-data-connect/reference/realtime.md +210 -0
- package/dist/global-skills/firebase-data-connect/reference/schema.md +290 -0
- package/dist/global-skills/firebase-data-connect/reference/sdk_admin_node.md +141 -0
- package/dist/global-skills/firebase-data-connect/reference/sdk_android.md +126 -0
- package/dist/global-skills/firebase-data-connect/reference/sdk_flutter.md +134 -0
- package/dist/global-skills/firebase-data-connect/reference/sdk_ios.md +157 -0
- package/dist/global-skills/firebase-data-connect/reference/sdk_web.md +146 -0
- package/dist/global-skills/firebase-data-connect/reference/search.md +264 -0
- package/dist/global-skills/firebase-data-connect/reference/security.md +295 -0
- package/dist/global-skills/firebase-data-connect/templates.md +318 -0
- package/dist/global-skills/firebase-firestore/SKILL.md +89 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/android_sdk_usage.md +230 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/data_model.md +66 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/flutter_setup.md +180 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/indexes.md +135 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/ios_setup.md +189 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/provisioning.md +118 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/python_sdk_usage.md +138 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/security_rules.md +577 -0
- package/dist/global-skills/firebase-firestore/references/enterprise/web_sdk_usage.md +127 -0
- package/dist/global-skills/firebase-firestore/references/standard/android_sdk_usage.md +193 -0
- package/dist/global-skills/firebase-firestore/references/standard/flutter_setup.md +176 -0
- package/dist/global-skills/firebase-firestore/references/standard/indexes.md +113 -0
- package/dist/global-skills/firebase-firestore/references/standard/ios_setup.md +174 -0
- package/dist/global-skills/firebase-firestore/references/standard/provisioning.md +110 -0
- package/dist/global-skills/firebase-firestore/references/standard/security_rules.md +577 -0
- package/dist/global-skills/firebase-firestore/references/standard/web_sdk_usage.md +192 -0
- package/dist/global-skills/firebase-hosting-basics/SKILL.md +64 -0
- package/dist/global-skills/firebase-hosting-basics/references/configuration.md +115 -0
- package/dist/global-skills/firebase-hosting-basics/references/deploying.md +48 -0
- package/dist/global-skills/firebase-remote-config-basics/SKILL.md +124 -0
- package/dist/global-skills/firebase-remote-config-basics/references/android_setup.md +91 -0
- package/dist/global-skills/firebase-remote-config-basics/references/ios_setup.md +89 -0
- package/dist/global-skills/firebase-security-rules-auditor/SKILL.md +70 -0
- package/dist/global-skills/go-live/SKILL.md +90 -0
- package/dist/global-skills/harden/SKILL.md +101 -0
- package/dist/global-skills/instrument-feature-flags/SKILL.md +88 -0
- package/dist/global-skills/instrument-feature-flags/references/adding-feature-flag-code.md +3578 -0
- package/dist/global-skills/instrument-feature-flags/references/android.md +146 -0
- package/dist/global-skills/instrument-feature-flags/references/api.md +194 -0
- package/dist/global-skills/instrument-feature-flags/references/best-practices.md +231 -0
- package/dist/global-skills/instrument-feature-flags/references/django.md +263 -0
- package/dist/global-skills/instrument-feature-flags/references/dotnet.md +763 -0
- package/dist/global-skills/instrument-feature-flags/references/elixir.md +47 -0
- package/dist/global-skills/instrument-feature-flags/references/flask.md +131 -0
- package/dist/global-skills/instrument-feature-flags/references/flutter.md +212 -0
- package/dist/global-skills/instrument-feature-flags/references/go.md +208 -0
- package/dist/global-skills/instrument-feature-flags/references/ios.md +146 -0
- package/dist/global-skills/instrument-feature-flags/references/java.md +94 -0
- package/dist/global-skills/instrument-feature-flags/references/laravel.md +170 -0
- package/dist/global-skills/instrument-feature-flags/references/next-js.md +383 -0
- package/dist/global-skills/instrument-feature-flags/references/nodejs.md +216 -0
- package/dist/global-skills/instrument-feature-flags/references/php.md +187 -0
- package/dist/global-skills/instrument-feature-flags/references/python.md +191 -0
- package/dist/global-skills/instrument-feature-flags/references/react-native.md +166 -0
- package/dist/global-skills/instrument-feature-flags/references/react.md +302 -0
- package/dist/global-skills/instrument-feature-flags/references/ruby-on-rails.md +604 -0
- package/dist/global-skills/instrument-feature-flags/references/ruby.md +200 -0
- package/dist/global-skills/instrument-feature-flags/references/rust.md +222 -0
- package/dist/global-skills/instrument-feature-flags/references/usage.md +600 -0
- package/dist/global-skills/instrument-feature-flags/references/web.md +193 -0
- package/dist/global-skills/instrument-product-analytics/SKILL.md +139 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-android.md +1639 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-angular.md +944 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-hybrid.md +1001 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-ssr.md +1004 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-static.md +720 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-astro-view-transitions.md +810 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-django.md +1167 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-expo.md +1412 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-fastapi.md +1585 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-flask.md +1208 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-laravel.md +2267 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-next-app-router.md +712 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-next-pages-router.md +767 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-nuxt-3-6.md +939 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-nuxt-4.md +1078 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-php.md +527 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-python.md +481 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-native.md +1823 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-react-router-6.md +582 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-react-router-7-data.md +892 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-react-router-7-declarative.md +649 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-react-router-7-framework.md +1218 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-tanstack-router-code-based.md +793 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-react-tanstack-router-file-based.md +780 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby-on-rails.md +1320 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-ruby.md +452 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-sveltekit.md +854 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-swift.md +665 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-tanstack-start.md +1199 -0
- package/dist/global-skills/instrument-product-analytics/references/EXAMPLE-vue-3.md +910 -0
- package/dist/global-skills/instrument-product-analytics/references/android.md +811 -0
- package/dist/global-skills/instrument-product-analytics/references/angular.md +376 -0
- package/dist/global-skills/instrument-product-analytics/references/astro.md +165 -0
- package/dist/global-skills/instrument-product-analytics/references/configuration.md +299 -0
- package/dist/global-skills/instrument-product-analytics/references/django.md +263 -0
- package/dist/global-skills/instrument-product-analytics/references/dotnet.md +763 -0
- package/dist/global-skills/instrument-product-analytics/references/elixir.md +414 -0
- package/dist/global-skills/instrument-product-analytics/references/flask.md +131 -0
- package/dist/global-skills/instrument-product-analytics/references/flutter.md +845 -0
- package/dist/global-skills/instrument-product-analytics/references/go.md +567 -0
- package/dist/global-skills/instrument-product-analytics/references/identify-users.md +272 -0
- package/dist/global-skills/instrument-product-analytics/references/ios.md +154 -0
- package/dist/global-skills/instrument-product-analytics/references/laravel.md +170 -0
- package/dist/global-skills/instrument-product-analytics/references/next-js.md +383 -0
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js-3-6.md +244 -0
- package/dist/global-skills/instrument-product-analytics/references/nuxt-js.md +253 -0
- package/dist/global-skills/instrument-product-analytics/references/php.md +646 -0
- package/dist/global-skills/instrument-product-analytics/references/posthog-python.md +1675 -0
- package/dist/global-skills/instrument-product-analytics/references/python.md +898 -0
- package/dist/global-skills/instrument-product-analytics/references/react-native.md +1338 -0
- package/dist/global-skills/instrument-product-analytics/references/react-router-v6.md +376 -0
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-data-mode.md +364 -0
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-declarative-mode.md +376 -0
- package/dist/global-skills/instrument-product-analytics/references/react-router-v7-framework-mode.md +479 -0
- package/dist/global-skills/instrument-product-analytics/references/ruby-on-rails.md +604 -0
- package/dist/global-skills/instrument-product-analytics/references/ruby.md +759 -0
- package/dist/global-skills/instrument-product-analytics/references/svelte.md +234 -0
- package/dist/global-skills/instrument-product-analytics/references/tanstack-start.md +193 -0
- package/dist/global-skills/instrument-product-analytics/references/usage.md +600 -0
- package/dist/global-skills/instrument-product-analytics/references/vue-js.md +306 -0
- package/dist/global-skills/manifest.json +125 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/SKILL.md +284 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/connection-configs.md +298 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/development-workflow.md +304 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/mcp-troubleshooting.md +55 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/output-diagnostics.md +150 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/pipeline-patterns.md +457 -0
- package/dist/global-skills/mongodb-atlas-stream-processing/references/sizing-and-parallelism.md +178 -0
- package/dist/global-skills/mongodb-connection/SKILL.md +201 -0
- package/dist/global-skills/mongodb-connection/references/monitoring-guide.md +191 -0
- package/dist/global-skills/mongodb-mcp-setup/SKILL.md +324 -0
- package/dist/global-skills/mongodb-natural-language-querying/SKILL.md +195 -0
- package/dist/global-skills/mongodb-query-optimizer/SKILL.md +150 -0
- package/dist/global-skills/mongodb-query-optimizer/references/aggregation-optimization.md +210 -0
- package/dist/global-skills/mongodb-query-optimizer/references/antipattern-examples.md +74 -0
- package/dist/global-skills/mongodb-query-optimizer/references/core-indexing-principles.md +134 -0
- package/dist/global-skills/mongodb-query-optimizer/references/update-query-examples.md +39 -0
- package/dist/global-skills/mongodb-schema-design/SKILL.md +181 -0
- package/dist/global-skills/mongodb-schema-design/references/antipattern-excessive-lookups.md +84 -0
- package/dist/global-skills/mongodb-schema-design/references/antipattern-unnecessary-collections.md +91 -0
- package/dist/global-skills/mongodb-schema-design/references/antipattern-unnecessary-indexes.md +95 -0
- package/dist/global-skills/mongodb-schema-design/references/fundamental-document-model.md +91 -0
- package/dist/global-skills/mongodb-schema-design/references/fundamental-document-size.md +226 -0
- package/dist/global-skills/mongodb-schema-design/references/fundamental-embed-vs-reference.md +418 -0
- package/dist/global-skills/mongodb-schema-design/references/fundamental-schema-validation.md +131 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-approximation.md +80 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-archive.md +143 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-attribute.md +77 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-bucket.md +102 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-computed.md +162 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-document-versioning.md +166 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-extended-reference.md +72 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-outlier.md +159 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-polymorphic.md +167 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-schema-versioning.md +273 -0
- package/dist/global-skills/mongodb-schema-design/references/pattern-time-series-collections.md +190 -0
- package/dist/global-skills/mongodb-schema-design/references/source-query-stats.md +123 -0
- package/dist/global-skills/mongodb-schema-design/references/source-slow-query-logs.md +63 -0
- package/dist/global-skills/mongodb-search-and-ai/SKILL.md +142 -0
- package/dist/global-skills/mongodb-search-and-ai/references/hybrid-search.md +697 -0
- package/dist/global-skills/mongodb-search-and-ai/references/lexical-search-indexing.md +584 -0
- package/dist/global-skills/mongodb-search-and-ai/references/lexical-search-querying.md +636 -0
- package/dist/global-skills/mongodb-search-and-ai/references/vector-search.md +746 -0
- package/dist/global-skills/native-data-fetching/SKILL.md +505 -0
- package/dist/global-skills/native-data-fetching/agents/openai.yaml +4 -0
- package/dist/global-skills/native-data-fetching/references/expo-router-loaders.md +341 -0
- package/dist/global-skills/neon/SKILL.md +343 -0
- package/dist/global-skills/neon-ai-gateway/SKILL.md +236 -0
- package/dist/global-skills/neon-functions/SKILL.md +490 -0
- package/dist/global-skills/neon-functions/references/ai-sdk.md +139 -0
- package/dist/global-skills/neon-functions/references/hono-websockets.md +145 -0
- package/dist/global-skills/neon-functions/references/mastra-studio.md +127 -0
- package/dist/global-skills/neon-functions/references/mcp.md +137 -0
- package/dist/global-skills/neon-functions/references/sentry.md +131 -0
- package/dist/global-skills/neon-functions/references/sse.md +143 -0
- package/dist/global-skills/neon-object-storage/SKILL.md +197 -0
- package/dist/global-skills/neon-postgres/SKILL.md +376 -0
- package/dist/global-skills/neon-postgres-branches/SKILL.md +281 -0
- package/dist/global-skills/neon-postgres-egress-optimizer/SKILL.md +247 -0
- package/dist/global-skills/onboarding/SKILL.md +101 -0
- package/dist/global-skills/plan-my-idea/SKILL.md +67 -0
- package/dist/global-skills/publish-app/SKILL.md +72 -0
- package/dist/global-skills/publish-extension/SKILL.md +47 -0
- package/dist/global-skills/resend/SKILL.md +294 -0
- package/dist/global-skills/resend/references/api-keys.md +98 -0
- package/dist/global-skills/resend/references/automations.md +228 -0
- package/dist/global-skills/resend/references/broadcasts.md +125 -0
- package/dist/global-skills/resend/references/contact-properties.md +111 -0
- package/dist/global-skills/resend/references/contacts.md +174 -0
- package/dist/global-skills/resend/references/domains.md +179 -0
- package/dist/global-skills/resend/references/events.md +119 -0
- package/dist/global-skills/resend/references/fetch-all-templates.mjs +37 -0
- package/dist/global-skills/resend/references/installation.md +142 -0
- package/dist/global-skills/resend/references/logs.md +161 -0
- package/dist/global-skills/resend/references/receiving.md +287 -0
- package/dist/global-skills/resend/references/segments.md +77 -0
- package/dist/global-skills/resend/references/sending/batch-email-examples.md +807 -0
- package/dist/global-skills/resend/references/sending/best-practices.md +453 -0
- package/dist/global-skills/resend/references/sending/email-management.md +135 -0
- package/dist/global-skills/resend/references/sending/overview.md +209 -0
- package/dist/global-skills/resend/references/sending/single-email-examples.md +470 -0
- package/dist/global-skills/resend/references/templates.md +202 -0
- package/dist/global-skills/resend/references/topics.md +104 -0
- package/dist/global-skills/resend/references/webhooks.md +317 -0
- package/dist/global-skills/reset-password/SKILL.md +59 -0
- package/dist/global-skills/save-data/SKILL.md +70 -0
- package/dist/global-skills/sentry-sdk-setup/SKILL.md +116 -0
- package/dist/global-skills/sentry-workflow/SKILL.md +32 -0
- package/dist/global-skills/setup-email/SKILL.md +69 -0
- package/dist/global-skills/setup-payments/SKILL.md +82 -0
- package/dist/global-skills/setup-sms/SKILL.md +51 -0
- package/dist/global-skills/sign-in-with-email-link/SKILL.md +53 -0
- package/dist/global-skills/sign-in-with-google/SKILL.md +68 -0
- package/dist/global-skills/sign-in-with-phone/SKILL.md +53 -0
- package/dist/global-skills/stripe-best-practices/SKILL.md +48 -0
- package/dist/global-skills/stripe-best-practices/references/billing.md +58 -0
- package/dist/global-skills/stripe-best-practices/references/connect.md +173 -0
- package/dist/global-skills/stripe-best-practices/references/payments.md +79 -0
- package/dist/global-skills/stripe-best-practices/references/security.md +109 -0
- package/dist/global-skills/stripe-best-practices/references/tax.md +37 -0
- package/dist/global-skills/stripe-best-practices/references/treasury.md +16 -0
- package/dist/global-skills/supabase/CHANGELOG.md +53 -0
- package/dist/global-skills/supabase/SKILL.md +145 -0
- package/dist/global-skills/supabase/assets/feedback-issue-template.md +17 -0
- package/dist/global-skills/supabase/references/skill-feedback.md +17 -0
- package/dist/global-skills/supabase-postgres-best-practices/CHANGELOG.md +43 -0
- package/dist/global-skills/supabase-postgres-best-practices/SKILL.md +64 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/_sections.md +39 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/_template.md +34 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
- package/dist/global-skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
- package/dist/global-skills/track-errors/SKILL.md +67 -0
- package/dist/global-skills/update-kit/SKILL.md +75 -0
- package/dist/global-skills/upgrading-expo/SKILL.md +134 -0
- package/dist/global-skills/upgrading-expo/agents/openai.yaml +4 -0
- package/dist/global-skills/upgrading-expo/references/expo-av-to-audio.md +132 -0
- package/dist/global-skills/upgrading-expo/references/expo-av-to-video.md +160 -0
- package/dist/global-skills/upgrading-expo/references/native-tabs.md +124 -0
- package/dist/global-skills/upgrading-expo/references/new-architecture.md +79 -0
- package/dist/global-skills/upgrading-expo/references/react-19.md +79 -0
- package/dist/global-skills/upgrading-expo/references/react-compiler.md +59 -0
- package/dist/global-skills/upgrading-expo/references/react-navigation-to-expo-router.md +61 -0
- package/dist/global-skills/use-dom/SKILL.md +417 -0
- package/dist/global-skills/use-dom/agents/openai.yaml +4 -0
- package/dist/global-skills/use-kit-mcp/SKILL.md +100 -0
- package/dist/global-skills/use-railway/SKILL.md +357 -0
- package/dist/global-skills/use-railway/references/analyze-db-mongo.md +84 -0
- package/dist/global-skills/use-railway/references/analyze-db-mysql.md +254 -0
- package/dist/global-skills/use-railway/references/analyze-db-postgres.md +479 -0
- package/dist/global-skills/use-railway/references/analyze-db-redis.md +208 -0
- package/dist/global-skills/use-railway/references/analyze-db.md +344 -0
- package/dist/global-skills/use-railway/references/configure.md +359 -0
- package/dist/global-skills/use-railway/references/deploy.md +225 -0
- package/dist/global-skills/use-railway/references/feature-flags.md +89 -0
- package/dist/global-skills/use-railway/references/iac.md +108 -0
- package/dist/global-skills/use-railway/references/operate.md +273 -0
- package/dist/global-skills/use-railway/references/request.md +262 -0
- package/dist/global-skills/use-railway/references/sandbox.md +167 -0
- package/dist/global-skills/use-railway/references/setup.md +364 -0
- package/dist/global-skills/use-railway/scripts/analyze-mongo.py +1549 -0
- package/dist/global-skills/use-railway/scripts/analyze-mysql.py +1195 -0
- package/dist/global-skills/use-railway/scripts/analyze-postgres.py +3058 -0
- package/dist/global-skills/use-railway/scripts/analyze-redis.py +1090 -0
- package/dist/global-skills/use-railway/scripts/dal.py +671 -0
- package/dist/global-skills/use-railway/scripts/enable-pg-stats.py +170 -0
- package/dist/global-skills/use-railway/scripts/pg-extensions.py +370 -0
- package/dist/global-skills/use-railway/scripts/railway-api.sh +52 -0
- package/dist/global-skills/vercel-composition-patterns/AGENTS.md +946 -0
- package/dist/global-skills/vercel-composition-patterns/README.md +60 -0
- package/dist/global-skills/vercel-composition-patterns/SKILL.md +89 -0
- package/dist/global-skills/vercel-composition-patterns/metadata.json +11 -0
- package/dist/global-skills/vercel-composition-patterns/rules/_sections.md +29 -0
- package/dist/global-skills/vercel-composition-patterns/rules/_template.md +24 -0
- package/dist/global-skills/vercel-composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/dist/global-skills/vercel-composition-patterns/rules/architecture-compound-components.md +112 -0
- package/dist/global-skills/vercel-composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/dist/global-skills/vercel-composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/dist/global-skills/vercel-composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/dist/global-skills/vercel-composition-patterns/rules/state-context-interface.md +191 -0
- package/dist/global-skills/vercel-composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/dist/global-skills/vercel-composition-patterns/rules/state-lift-state.md +125 -0
- package/dist/global-skills/vercel-react-best-practices/AGENTS.md +3810 -0
- package/dist/global-skills/vercel-react-best-practices/README.md +123 -0
- package/dist/global-skills/vercel-react-best-practices/SKILL.md +149 -0
- package/dist/global-skills/vercel-react-best-practices/metadata.json +15 -0
- package/dist/global-skills/vercel-react-best-practices/rules/_sections.md +46 -0
- package/dist/global-skills/vercel-react-best-practices/rules/_template.md +28 -0
- package/dist/global-skills/vercel-react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/dist/global-skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/dist/global-skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
- package/dist/global-skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-defer-await.md +82 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
- package/dist/global-skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/dist/global-skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
- package/dist/global-skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
- package/dist/global-skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/dist/global-skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/dist/global-skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/dist/global-skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/dist/global-skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/dist/global-skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
- package/dist/global-skills/web-to-native/SKILL.md +83 -0
- package/dist/global-skills/web-to-native/references/false-friends.md +119 -0
- package/dist/global-skills/web-to-native/references/native-patterns.md +39 -0
- package/dist/global-skills/web-to-native/references/run-as-goal.md +48 -0
- package/dist/global-skills/web-to-native/references/verify-on-device.md +45 -0
- package/dist/global-skills/wire-auth/SKILL.md +28 -0
- package/dist/global-skills/wire-database/SKILL.md +28 -0
- package/dist/global-skills/wire-email/SKILL.md +27 -0
- package/dist/global-skills/wire-payments/SKILL.md +27 -0
- package/dist/global-skills/workers-best-practices/SKILL.md +127 -0
- package/dist/global-skills/workers-best-practices/references/review.md +174 -0
- package/dist/global-skills/workers-best-practices/references/rules.md +463 -0
- package/dist/global-skills/wrangler/SKILL.md +922 -0
- package/dist/global-skills/xcode-project-setup/SKILL.md +140 -0
- package/dist/global-skills/xcode-project-setup/scripts/xcode_spm_setup/Package.resolved +41 -0
- package/dist/global-skills/xcode-project-setup/scripts/xcode_spm_setup/Package.swift +17 -0
- package/dist/global-skills/xcode-project-setup/scripts/xcode_spm_setup/Sources/main.swift +232 -0
- package/package.json +21 -19
- package/LICENSE.md +0 -47
- package/dist/chunk-HFT4CUOY.js +0 -13381
- package/dist/index.js +0 -7
|
@@ -0,0 +1,1320 @@
|
|
|
1
|
+
# PostHog ruby-on-rails Example Project
|
|
2
|
+
|
|
3
|
+
Repository: https://github.com/PostHog/context-mill
|
|
4
|
+
Path: example-apps/ruby-on-rails
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## README.md
|
|
9
|
+
|
|
10
|
+
# PostHog Ruby on Rails example
|
|
11
|
+
|
|
12
|
+
This is a [Ruby on Rails](https://rubyonrails.org) example demonstrating PostHog integration with product analytics, error tracking (auto-instrumentation), feature flags, user identification, and ActiveJob instrumentation via the `posthog-rails` gem.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **Product analytics**: Track user events and behaviors with `PostHog.capture`
|
|
17
|
+
- **Error tracking (auto)**: Unhandled exceptions captured automatically by `posthog-rails`
|
|
18
|
+
- **Error tracking (manual)**: Handled errors captured with `PostHog.capture_exception`
|
|
19
|
+
- **Rails.error integration**: Rails 7+ error reporting captured automatically
|
|
20
|
+
- **ActiveJob instrumentation**: Background job failures captured automatically
|
|
21
|
+
- **User identification**: Associate events with authenticated users via `PostHog.identify`
|
|
22
|
+
- **Feature flags**: Control feature rollouts with `PostHog.is_feature_enabled`
|
|
23
|
+
- **User context**: Exceptions automatically associated with `current_user`
|
|
24
|
+
- **Frontend tracking**: posthog-js captures pageviews and session replay alongside backend events
|
|
25
|
+
|
|
26
|
+
## Getting started
|
|
27
|
+
|
|
28
|
+
### 1. Install dependencies
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bundle install
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Configure environment variables
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cp .env.example .env
|
|
38
|
+
# Edit .env and add your PostHog project token
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Get your PostHog project token from your [PostHog project settings](https://app.posthog.com/project/settings).
|
|
42
|
+
|
|
43
|
+
### 3. Setup database
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
bin/rails db:create db:migrate db:seed
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 4. Run the development server
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
bin/rails server
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser. Login with `admin@example.com` / `admin`.
|
|
56
|
+
|
|
57
|
+
## Project structure
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
ruby-on-rails/
|
|
61
|
+
├── config/
|
|
62
|
+
│ ├── routes.rb # URL routing
|
|
63
|
+
│ └── initializers/
|
|
64
|
+
│ └── posthog.rb # PostHog + posthog-rails configuration
|
|
65
|
+
├── app/
|
|
66
|
+
│ ├── controllers/
|
|
67
|
+
│ │ ├── application_controller.rb # Base controller with current_user
|
|
68
|
+
│ │ ├── sessions_controller.rb # Login/logout with PostHog identify
|
|
69
|
+
│ │ ├── registrations_controller.rb # Signup with PostHog identify
|
|
70
|
+
│ │ ├── dashboard_controller.rb # Feature flags + ActiveJob demo
|
|
71
|
+
│ │ ├── burritos_controller.rb # Custom event tracking
|
|
72
|
+
│ │ ├── profiles_controller.rb # Page view tracking
|
|
73
|
+
│ │ └── errors_controller.rb # Error tracking demos
|
|
74
|
+
│ ├── jobs/
|
|
75
|
+
│ │ └── example_job.rb # ActiveJob auto-instrumentation demo
|
|
76
|
+
│ ├── models/
|
|
77
|
+
│ │ └── user.rb # posthog_distinct_id + posthog_properties
|
|
78
|
+
│ └── views/
|
|
79
|
+
│ ├── layouts/application.html.erb # Base layout with posthog-js snippet
|
|
80
|
+
│ ├── sessions/new.html.erb # Login page
|
|
81
|
+
│ ├── registrations/new.html.erb # Signup page
|
|
82
|
+
│ ├── dashboard/show.html.erb # Feature flags demo
|
|
83
|
+
│ ├── burritos/show.html.erb # Event tracking demo
|
|
84
|
+
│ └── profiles/show.html.erb # Error tracking demo
|
|
85
|
+
├── db/
|
|
86
|
+
│ ├── migrate/ # Database migrations
|
|
87
|
+
│ └── seeds.rb # Default admin user
|
|
88
|
+
├── .env.example # Environment variable template
|
|
89
|
+
├── Gemfile # Ruby dependencies
|
|
90
|
+
└── README.md # This file
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Key integration points
|
|
94
|
+
|
|
95
|
+
### PostHog initialization (config/initializers/posthog.rb)
|
|
96
|
+
|
|
97
|
+
```ruby
|
|
98
|
+
# Rails-specific auto-instrumentation
|
|
99
|
+
PostHog::Rails.configure do |config|
|
|
100
|
+
config.auto_capture_exceptions = true
|
|
101
|
+
config.report_rescued_exceptions = true
|
|
102
|
+
config.auto_instrument_active_job = true
|
|
103
|
+
config.capture_user_context = true
|
|
104
|
+
config.current_user_method = :current_user
|
|
105
|
+
config.user_id_method = :posthog_distinct_id
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
PostHog.init do |config|
|
|
109
|
+
config.api_key = ENV.fetch('POSTHOG_PROJECT_TOKEN', nil)
|
|
110
|
+
config.host = ENV.fetch('POSTHOG_HOST', 'https://us.i.posthog.com')
|
|
111
|
+
end
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### User model (app/models/user.rb)
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
class User < ApplicationRecord
|
|
118
|
+
has_secure_password
|
|
119
|
+
|
|
120
|
+
# Called by posthog-rails for automatic user association in error reports
|
|
121
|
+
def posthog_distinct_id
|
|
122
|
+
email
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def posthog_properties
|
|
126
|
+
{ email: email, is_staff: is_staff, date_joined: created_at&.iso8601 }
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### User identification (app/controllers/sessions_controller.rb)
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
# Identify the user and capture login event
|
|
135
|
+
PostHog.identify(
|
|
136
|
+
distinct_id: user.posthog_distinct_id,
|
|
137
|
+
properties: user.posthog_properties
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
PostHog.capture(
|
|
141
|
+
distinct_id: user.posthog_distinct_id,
|
|
142
|
+
event: 'user_logged_in',
|
|
143
|
+
properties: { login_method: 'email' }
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Feature flags (app/controllers/dashboard_controller.rb)
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
# Check if a feature flag is enabled
|
|
151
|
+
@show_new_feature = PostHog.is_feature_enabled(
|
|
152
|
+
'new-dashboard-feature',
|
|
153
|
+
user.posthog_distinct_id,
|
|
154
|
+
person_properties: user.posthog_properties
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Get feature flag payload for configuration
|
|
158
|
+
@feature_config = PostHog.get_feature_flag_payload(
|
|
159
|
+
'new-dashboard-feature',
|
|
160
|
+
user.posthog_distinct_id
|
|
161
|
+
)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Error tracking — auto-capture
|
|
165
|
+
|
|
166
|
+
With `auto_capture_exceptions: true`, unhandled exceptions in controllers are captured automatically. No code needed:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
# This exception is automatically captured by posthog-rails
|
|
170
|
+
# with the current_user's posthog_distinct_id attached
|
|
171
|
+
def show
|
|
172
|
+
raise "Something went wrong" # Captured automatically!
|
|
173
|
+
end
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Error tracking — manual capture
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
begin
|
|
180
|
+
risky_operation
|
|
181
|
+
rescue => e
|
|
182
|
+
PostHog.capture_exception(e, current_user.posthog_distinct_id)
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Error tracking — Rails.error integration
|
|
187
|
+
|
|
188
|
+
```ruby
|
|
189
|
+
# posthog-rails subscribes to Rails.error automatically
|
|
190
|
+
Rails.error.handle(context: { user_id: user.id }) do
|
|
191
|
+
risky_operation
|
|
192
|
+
end
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### ActiveJob instrumentation
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
# config: auto_instrument_active_job = true
|
|
199
|
+
# Job failures are captured automatically.
|
|
200
|
+
# Use the posthog_distinct_id DSL to associate errors with a user.
|
|
201
|
+
class ExampleJob < ApplicationJob
|
|
202
|
+
posthog_distinct_id ->(distinct_id, *) { distinct_id }
|
|
203
|
+
|
|
204
|
+
def perform(distinct_id, should_fail: false)
|
|
205
|
+
raise "Job failed" # Captured automatically with user context
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# In the controller, pass the distinct_id when enqueuing:
|
|
210
|
+
ExampleJob.perform_later(current_user.posthog_distinct_id, should_fail: true)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Frontend + Backend integration
|
|
214
|
+
|
|
215
|
+
This example includes the posthog-js snippet in the layout template to demonstrate how frontend and backend tracking work together.
|
|
216
|
+
|
|
217
|
+
### How it works
|
|
218
|
+
|
|
219
|
+
1. **posthog-js** (frontend) captures pageviews, clicks, and session replay
|
|
220
|
+
2. **posthog-ruby + posthog-rails** (backend) captures business logic events, errors, and feature flag evaluations
|
|
221
|
+
3. **Shared distinct_id** — frontend and backend events are linked when the same `distinct_id` is used on both sides. Call `posthog.identify(user.email)` in posthog-js after login, matching the `posthog_distinct_id` used on the backend
|
|
222
|
+
4. **Session replay** lets you watch user sessions where errors occurred
|
|
223
|
+
|
|
224
|
+
**Note:** Unlike the Django SDK, posthog-rails does not include a context middleware that reads `X-POSTHOG-SESSION-ID` or `X-POSTHOG-DISTINCT-ID` tracing headers. Frontend and backend events are correlated through the shared `distinct_id`.
|
|
225
|
+
|
|
226
|
+
### When to track frontend vs backend
|
|
227
|
+
|
|
228
|
+
- **Frontend**: UI interactions, client-side errors, session replay, pageviews
|
|
229
|
+
- **Backend**: Business logic (signups, purchases), server errors, feature flag evaluations, background jobs
|
|
230
|
+
|
|
231
|
+
## Learn more
|
|
232
|
+
|
|
233
|
+
- [PostHog Ruby on Rails integration](https://posthog.com/docs/libraries/ruby-on-rails)
|
|
234
|
+
- [PostHog Ruby SDK](https://posthog.com/docs/libraries/ruby)
|
|
235
|
+
- [PostHog Error Tracking](https://posthog.com/docs/error-tracking)
|
|
236
|
+
- [Ruby on Rails documentation](https://guides.rubyonrails.org/)
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## .env.example
|
|
241
|
+
|
|
242
|
+
```example
|
|
243
|
+
# PostHog Configuration
|
|
244
|
+
POSTHOG_PROJECT_TOKEN=phc_your_project_token_here
|
|
245
|
+
POSTHOG_HOST=https://us.i.posthog.com
|
|
246
|
+
|
|
247
|
+
# Optional: Enable debug mode to see PostHog requests
|
|
248
|
+
# POSTHOG_DEBUG=true
|
|
249
|
+
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## app/controllers/application_controller.rb
|
|
255
|
+
|
|
256
|
+
```rb
|
|
257
|
+
class ApplicationController < ActionController::Base
|
|
258
|
+
protect_from_forgery with: :exception
|
|
259
|
+
|
|
260
|
+
private
|
|
261
|
+
|
|
262
|
+
def current_user
|
|
263
|
+
@current_user ||= User.find_by(id: session[:user_id]) if session[:user_id]
|
|
264
|
+
end
|
|
265
|
+
helper_method :current_user
|
|
266
|
+
|
|
267
|
+
def require_login
|
|
268
|
+
unless current_user
|
|
269
|
+
redirect_to login_path
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## app/controllers/burritos_controller.rb
|
|
279
|
+
|
|
280
|
+
```rb
|
|
281
|
+
class BurritosController < ApplicationController
|
|
282
|
+
before_action :require_login
|
|
283
|
+
|
|
284
|
+
def show
|
|
285
|
+
@burrito_count = session[:burrito_count] || 0
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def consider
|
|
289
|
+
count = (session[:burrito_count] || 0) + 1
|
|
290
|
+
session[:burrito_count] = count
|
|
291
|
+
|
|
292
|
+
user = current_user
|
|
293
|
+
|
|
294
|
+
# PostHog: Track custom event
|
|
295
|
+
PostHog.identify(
|
|
296
|
+
distinct_id: user.posthog_distinct_id,
|
|
297
|
+
properties: user.posthog_properties
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
PostHog.capture(
|
|
301
|
+
distinct_id: user.posthog_distinct_id,
|
|
302
|
+
event: 'burrito_considered',
|
|
303
|
+
properties: { total_considerations: count }
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
render json: { success: true, count: count }
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## app/controllers/dashboard_controller.rb
|
|
315
|
+
|
|
316
|
+
```rb
|
|
317
|
+
class DashboardController < ApplicationController
|
|
318
|
+
before_action :require_login
|
|
319
|
+
|
|
320
|
+
def show
|
|
321
|
+
user = current_user
|
|
322
|
+
|
|
323
|
+
# PostHog: Track dashboard view
|
|
324
|
+
PostHog.capture(
|
|
325
|
+
distinct_id: user.posthog_distinct_id,
|
|
326
|
+
event: 'dashboard_viewed',
|
|
327
|
+
properties: { is_staff: user.is_staff }
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
# PostHog: Check feature flag
|
|
331
|
+
@show_new_feature = PostHog.is_feature_enabled(
|
|
332
|
+
'new-dashboard-feature',
|
|
333
|
+
user.posthog_distinct_id,
|
|
334
|
+
person_properties: user.posthog_properties
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
# PostHog: Get feature flag payload for configuration
|
|
338
|
+
@feature_config = PostHog.get_feature_flag_payload(
|
|
339
|
+
'new-dashboard-feature',
|
|
340
|
+
user.posthog_distinct_id
|
|
341
|
+
)
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def enqueue_test_job
|
|
345
|
+
# Enqueue a job that will fail — posthog-rails captures the error automatically.
|
|
346
|
+
# The distinct_id is passed so the posthog_distinct_id DSL can associate the error with this user.
|
|
347
|
+
ExampleJob.perform_later(current_user.posthog_distinct_id, should_fail: true)
|
|
348
|
+
|
|
349
|
+
render json: {
|
|
350
|
+
success: true,
|
|
351
|
+
message: 'Job enqueued. The job will fail and posthog-rails will capture the error automatically.'
|
|
352
|
+
}
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## app/controllers/errors_controller.rb
|
|
361
|
+
|
|
362
|
+
```rb
|
|
363
|
+
class ErrorsController < ApplicationController
|
|
364
|
+
before_action :require_login
|
|
365
|
+
|
|
366
|
+
def test
|
|
367
|
+
# Manual exception capture — catch the error and report it explicitly
|
|
368
|
+
begin
|
|
369
|
+
raise StandardError, 'Test exception from critical operation'
|
|
370
|
+
rescue StandardError => e
|
|
371
|
+
# PostHog: Manually capture the exception
|
|
372
|
+
PostHog.capture_exception(e, current_user.posthog_distinct_id)
|
|
373
|
+
|
|
374
|
+
PostHog.capture(
|
|
375
|
+
distinct_id: current_user.posthog_distinct_id,
|
|
376
|
+
event: 'error_triggered',
|
|
377
|
+
properties: {
|
|
378
|
+
error_type: e.class.name,
|
|
379
|
+
error_message: e.message
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
render json: {
|
|
384
|
+
success: false,
|
|
385
|
+
error: e.message,
|
|
386
|
+
message: 'Error has been captured by PostHog'
|
|
387
|
+
}, status: :internal_server_error
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def test_rails_error
|
|
392
|
+
# Rails.error.handle — Rails 7+ error reporting integration.
|
|
393
|
+
# posthog-rails subscribes to Rails.error, so exceptions reported
|
|
394
|
+
# via Rails.error.handle are automatically captured in PostHog.
|
|
395
|
+
Rails.error.handle(context: { user_id: current_user.id }) do
|
|
396
|
+
raise StandardError, 'Test error via Rails.error.handle — captured automatically by posthog-rails'
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
render json: {
|
|
400
|
+
success: true,
|
|
401
|
+
message: 'Error was handled via Rails.error.handle and captured by posthog-rails'
|
|
402
|
+
}
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## app/controllers/profiles_controller.rb
|
|
411
|
+
|
|
412
|
+
```rb
|
|
413
|
+
class ProfilesController < ApplicationController
|
|
414
|
+
before_action :require_login
|
|
415
|
+
|
|
416
|
+
def show
|
|
417
|
+
# PostHog: Track profile view
|
|
418
|
+
PostHog.capture(
|
|
419
|
+
distinct_id: current_user.posthog_distinct_id,
|
|
420
|
+
event: 'profile_viewed'
|
|
421
|
+
)
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
---
|
|
428
|
+
|
|
429
|
+
## app/controllers/registrations_controller.rb
|
|
430
|
+
|
|
431
|
+
```rb
|
|
432
|
+
class RegistrationsController < ApplicationController
|
|
433
|
+
def new
|
|
434
|
+
redirect_to dashboard_path if current_user
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
def create
|
|
438
|
+
user = User.new(
|
|
439
|
+
email: params[:email],
|
|
440
|
+
password: params[:password],
|
|
441
|
+
password_confirmation: params[:password_confirmation]
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
if user.save
|
|
445
|
+
session[:user_id] = user.id
|
|
446
|
+
|
|
447
|
+
# PostHog: Identify the new user and capture signup event
|
|
448
|
+
PostHog.identify(
|
|
449
|
+
distinct_id: user.posthog_distinct_id,
|
|
450
|
+
properties: user.posthog_properties
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
PostHog.capture(
|
|
454
|
+
distinct_id: user.posthog_distinct_id,
|
|
455
|
+
event: 'user_signed_up',
|
|
456
|
+
properties: { signup_method: 'form' }
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
redirect_to dashboard_path
|
|
460
|
+
else
|
|
461
|
+
flash[:error] = user.errors.full_messages.join(', ')
|
|
462
|
+
render :new, status: :unprocessable_entity
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## app/controllers/sessions_controller.rb
|
|
472
|
+
|
|
473
|
+
```rb
|
|
474
|
+
class SessionsController < ApplicationController
|
|
475
|
+
def new
|
|
476
|
+
redirect_to dashboard_path if current_user
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
def create
|
|
480
|
+
user = User.find_by(email: params[:email])
|
|
481
|
+
|
|
482
|
+
if user&.authenticate(params[:password])
|
|
483
|
+
session[:user_id] = user.id
|
|
484
|
+
|
|
485
|
+
# PostHog: Identify the user and capture login event
|
|
486
|
+
PostHog.identify(
|
|
487
|
+
distinct_id: user.posthog_distinct_id,
|
|
488
|
+
properties: user.posthog_properties
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
PostHog.capture(
|
|
492
|
+
distinct_id: user.posthog_distinct_id,
|
|
493
|
+
event: 'user_logged_in',
|
|
494
|
+
properties: { login_method: 'email' }
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
redirect_to dashboard_path
|
|
498
|
+
else
|
|
499
|
+
flash[:error] = 'Invalid email or password'
|
|
500
|
+
render :new, status: :unprocessable_entity
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def destroy
|
|
505
|
+
if current_user
|
|
506
|
+
# PostHog: Track logout before session ends
|
|
507
|
+
PostHog.capture(
|
|
508
|
+
distinct_id: current_user.posthog_distinct_id,
|
|
509
|
+
event: 'user_logged_out'
|
|
510
|
+
)
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
session.delete(:user_id)
|
|
514
|
+
redirect_to login_path
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## app/jobs/application_job.rb
|
|
523
|
+
|
|
524
|
+
```rb
|
|
525
|
+
class ApplicationJob < ActiveJob::Base
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## app/jobs/example_job.rb
|
|
533
|
+
|
|
534
|
+
```rb
|
|
535
|
+
# Example ActiveJob demonstrating posthog-rails auto-instrumentation.
|
|
536
|
+
#
|
|
537
|
+
# When auto_instrument_active_job is enabled in the PostHog config,
|
|
538
|
+
# posthog-rails automatically captures exceptions from failed jobs.
|
|
539
|
+
# The job class name, queue, and arguments are included as properties
|
|
540
|
+
# on the error event.
|
|
541
|
+
#
|
|
542
|
+
# Use the posthog_distinct_id DSL to associate job errors with a user.
|
|
543
|
+
# The proc receives the same arguments as perform and should return
|
|
544
|
+
# the distinct_id string. Without this, job errors have no user context.
|
|
545
|
+
class ExampleJob < ApplicationJob
|
|
546
|
+
queue_as :default
|
|
547
|
+
|
|
548
|
+
# Extract distinct_id from the first argument so posthog-rails
|
|
549
|
+
# can associate the error with the user who triggered the job.
|
|
550
|
+
posthog_distinct_id ->(distinct_id, *) { distinct_id }
|
|
551
|
+
|
|
552
|
+
def perform(distinct_id, should_fail: false)
|
|
553
|
+
if should_fail
|
|
554
|
+
raise StandardError, 'Example job failure - this error is automatically captured by posthog-rails'
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
Rails.logger.info "ExampleJob completed successfully for #{distinct_id}"
|
|
558
|
+
end
|
|
559
|
+
end
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## app/models/application_record.rb
|
|
566
|
+
|
|
567
|
+
```rb
|
|
568
|
+
class ApplicationRecord < ActiveRecord::Base
|
|
569
|
+
primary_abstract_class
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
---
|
|
575
|
+
|
|
576
|
+
## app/models/user.rb
|
|
577
|
+
|
|
578
|
+
```rb
|
|
579
|
+
class User < ApplicationRecord
|
|
580
|
+
has_secure_password
|
|
581
|
+
|
|
582
|
+
validates :email, presence: true, uniqueness: true
|
|
583
|
+
|
|
584
|
+
# Called by posthog-rails for automatic user association in error reports.
|
|
585
|
+
# When auto_capture_exceptions and capture_user_context are enabled,
|
|
586
|
+
# posthog-rails calls this method on current_user to get the distinct_id.
|
|
587
|
+
def posthog_distinct_id
|
|
588
|
+
email
|
|
589
|
+
end
|
|
590
|
+
|
|
591
|
+
# Helper used by controllers when calling PostHog.identify to set person properties.
|
|
592
|
+
# These properties appear on the person profile in PostHog.
|
|
593
|
+
def posthog_properties
|
|
594
|
+
{
|
|
595
|
+
email: email,
|
|
596
|
+
is_staff: is_staff,
|
|
597
|
+
date_joined: created_at&.iso8601
|
|
598
|
+
}
|
|
599
|
+
end
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## app/views/burritos/show.html.erb
|
|
607
|
+
|
|
608
|
+
```erb
|
|
609
|
+
<% content_for(:title) { 'Burrito - PostHog Rails example' } %>
|
|
610
|
+
|
|
611
|
+
<div class="card">
|
|
612
|
+
<h1>Burrito consideration tracker</h1>
|
|
613
|
+
<p>This page demonstrates custom event tracking with PostHog.</p>
|
|
614
|
+
</div>
|
|
615
|
+
|
|
616
|
+
<div class="card" style="text-align: center;">
|
|
617
|
+
<h2>Times considered</h2>
|
|
618
|
+
<div class="count" id="burrito-count"><%= @burrito_count %></div>
|
|
619
|
+
<button onclick="considerBurrito()" style="font-size: 18px; padding: 15px 30px;">
|
|
620
|
+
Consider a burrito
|
|
621
|
+
</button>
|
|
622
|
+
</div>
|
|
623
|
+
|
|
624
|
+
<div class="card">
|
|
625
|
+
<h3>How event tracking works</h3>
|
|
626
|
+
<p>Each time you click the button, a <code>burrito_considered</code> event is sent to PostHog:</p>
|
|
627
|
+
<pre style="background: #f3f4f6; padding: 15px; border-radius: 5px; overflow-x: auto; margin-top: 15px;"><code>PostHog.capture(
|
|
628
|
+
distinct_id: user.posthog_distinct_id,
|
|
629
|
+
event: 'burrito_considered',
|
|
630
|
+
properties: { total_considerations: count }
|
|
631
|
+
)</code></pre>
|
|
632
|
+
</div>
|
|
633
|
+
|
|
634
|
+
<% content_for :scripts do %>
|
|
635
|
+
<script>
|
|
636
|
+
async function considerBurrito() {
|
|
637
|
+
try {
|
|
638
|
+
const response = await fetch('/api/burrito/consider', {
|
|
639
|
+
method: 'POST',
|
|
640
|
+
headers: {
|
|
641
|
+
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
|
|
642
|
+
'Content-Type': 'application/json',
|
|
643
|
+
},
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
const data = await response.json();
|
|
647
|
+
|
|
648
|
+
if (data.success) {
|
|
649
|
+
document.getElementById('burrito-count').textContent = data.count;
|
|
650
|
+
}
|
|
651
|
+
} catch (error) {
|
|
652
|
+
console.error('Error:', error);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
</script>
|
|
656
|
+
<% end %>
|
|
657
|
+
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
---
|
|
661
|
+
|
|
662
|
+
## app/views/dashboard/show.html.erb
|
|
663
|
+
|
|
664
|
+
```erb
|
|
665
|
+
<% content_for(:title) { 'Dashboard - PostHog Rails example' } %>
|
|
666
|
+
|
|
667
|
+
<div class="card">
|
|
668
|
+
<h1>Dashboard</h1>
|
|
669
|
+
<p>Welcome back, <strong><%= current_user.email %></strong>!</p>
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
<div class="card">
|
|
673
|
+
<h2>Feature flags</h2>
|
|
674
|
+
<p>Feature flags allow you to control feature rollouts and run A/B tests.</p>
|
|
675
|
+
|
|
676
|
+
<% if @show_new_feature %>
|
|
677
|
+
<div class="feature-flag">
|
|
678
|
+
<h3>New feature enabled!</h3>
|
|
679
|
+
<p>
|
|
680
|
+
This section is only visible because the <code>new-dashboard-feature</code>
|
|
681
|
+
flag is enabled for your user.
|
|
682
|
+
</p>
|
|
683
|
+
<% if @feature_config %>
|
|
684
|
+
<p><strong>Feature config:</strong> <%= @feature_config %></p>
|
|
685
|
+
<% end %>
|
|
686
|
+
</div>
|
|
687
|
+
<% else %>
|
|
688
|
+
<div style="background: #f3f4f6; padding: 15px; border-radius: 8px; margin-top: 15px;">
|
|
689
|
+
<p>
|
|
690
|
+
The <code>new-dashboard-feature</code> flag is not enabled for your user.
|
|
691
|
+
Create this flag in your PostHog project to see it in action.
|
|
692
|
+
</p>
|
|
693
|
+
</div>
|
|
694
|
+
<% end %>
|
|
695
|
+
</div>
|
|
696
|
+
|
|
697
|
+
<div class="card">
|
|
698
|
+
<h2>ActiveJob instrumentation</h2>
|
|
699
|
+
<p>
|
|
700
|
+
Click below to enqueue a background job that will fail.
|
|
701
|
+
<code>posthog-rails</code> automatically captures the exception — no extra code needed.
|
|
702
|
+
</p>
|
|
703
|
+
<button onclick="enqueueTestJob()" style="margin-top: 10px;">Enqueue failing job</button>
|
|
704
|
+
<div id="job-result" style="margin-top: 15px; display: none;"></div>
|
|
705
|
+
</div>
|
|
706
|
+
|
|
707
|
+
<div class="card">
|
|
708
|
+
<h3>How feature flags work</h3>
|
|
709
|
+
<pre style="background: #f3f4f6; padding: 15px; border-radius: 5px; overflow-x: auto;"><code># Check if a feature flag is enabled
|
|
710
|
+
show_feature = PostHog.is_feature_enabled(
|
|
711
|
+
'new-dashboard-feature',
|
|
712
|
+
user.posthog_distinct_id,
|
|
713
|
+
person_properties: user.posthog_properties
|
|
714
|
+
)
|
|
715
|
+
|
|
716
|
+
# Get feature flag payload for configuration
|
|
717
|
+
config = PostHog.get_feature_flag_payload(
|
|
718
|
+
'new-dashboard-feature',
|
|
719
|
+
user.posthog_distinct_id
|
|
720
|
+
)</code></pre>
|
|
721
|
+
</div>
|
|
722
|
+
|
|
723
|
+
<% content_for :scripts do %>
|
|
724
|
+
<script>
|
|
725
|
+
async function enqueueTestJob() {
|
|
726
|
+
const resultDiv = document.getElementById('job-result');
|
|
727
|
+
try {
|
|
728
|
+
const response = await fetch('/api/test-job', {
|
|
729
|
+
method: 'POST',
|
|
730
|
+
headers: {
|
|
731
|
+
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
|
|
732
|
+
'Content-Type': 'application/json',
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
const data = await response.json();
|
|
736
|
+
resultDiv.style.display = 'block';
|
|
737
|
+
resultDiv.innerHTML = '<div class="flash success">' + data.message + '</div>';
|
|
738
|
+
} catch (error) {
|
|
739
|
+
resultDiv.style.display = 'block';
|
|
740
|
+
resultDiv.innerHTML = '<div class="flash error">Request failed: ' + error + '</div>';
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
</script>
|
|
744
|
+
<% end %>
|
|
745
|
+
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## app/views/layouts/application.html.erb
|
|
751
|
+
|
|
752
|
+
```erb
|
|
753
|
+
<!DOCTYPE html>
|
|
754
|
+
<html lang="en">
|
|
755
|
+
<head>
|
|
756
|
+
<meta charset="UTF-8">
|
|
757
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
758
|
+
<title><%= content_for?(:title) ? yield(:title) : 'PostHog Rails example' %></title>
|
|
759
|
+
<%= csrf_meta_tags %>
|
|
760
|
+
<style>
|
|
761
|
+
* {
|
|
762
|
+
box-sizing: border-box;
|
|
763
|
+
margin: 0;
|
|
764
|
+
padding: 0;
|
|
765
|
+
}
|
|
766
|
+
body {
|
|
767
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
|
|
768
|
+
line-height: 1.6;
|
|
769
|
+
background-color: #f5f5f5;
|
|
770
|
+
color: #333;
|
|
771
|
+
}
|
|
772
|
+
.container {
|
|
773
|
+
max-width: 800px;
|
|
774
|
+
margin: 0 auto;
|
|
775
|
+
padding: 20px;
|
|
776
|
+
}
|
|
777
|
+
nav {
|
|
778
|
+
background: #1d4ed8;
|
|
779
|
+
padding: 15px 20px;
|
|
780
|
+
margin-bottom: 30px;
|
|
781
|
+
}
|
|
782
|
+
nav a {
|
|
783
|
+
color: white;
|
|
784
|
+
text-decoration: none;
|
|
785
|
+
margin-right: 20px;
|
|
786
|
+
}
|
|
787
|
+
nav a:hover {
|
|
788
|
+
text-decoration: underline;
|
|
789
|
+
}
|
|
790
|
+
.card {
|
|
791
|
+
background: white;
|
|
792
|
+
border-radius: 8px;
|
|
793
|
+
padding: 20px;
|
|
794
|
+
margin-bottom: 20px;
|
|
795
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
796
|
+
}
|
|
797
|
+
h1, h2, h3 {
|
|
798
|
+
margin-bottom: 15px;
|
|
799
|
+
color: #1d4ed8;
|
|
800
|
+
}
|
|
801
|
+
button, .btn {
|
|
802
|
+
background: #1d4ed8;
|
|
803
|
+
color: white;
|
|
804
|
+
border: none;
|
|
805
|
+
padding: 10px 20px;
|
|
806
|
+
border-radius: 5px;
|
|
807
|
+
cursor: pointer;
|
|
808
|
+
font-size: 14px;
|
|
809
|
+
display: inline-block;
|
|
810
|
+
text-decoration: none;
|
|
811
|
+
}
|
|
812
|
+
button:hover, .btn:hover {
|
|
813
|
+
background: #1e40af;
|
|
814
|
+
}
|
|
815
|
+
button.danger {
|
|
816
|
+
background: #dc2626;
|
|
817
|
+
}
|
|
818
|
+
button.danger:hover {
|
|
819
|
+
background: #b91c1c;
|
|
820
|
+
}
|
|
821
|
+
input {
|
|
822
|
+
width: 100%;
|
|
823
|
+
padding: 10px;
|
|
824
|
+
margin-bottom: 15px;
|
|
825
|
+
border: 1px solid #ddd;
|
|
826
|
+
border-radius: 5px;
|
|
827
|
+
font-size: 14px;
|
|
828
|
+
}
|
|
829
|
+
.flash {
|
|
830
|
+
padding: 10px 15px;
|
|
831
|
+
border-radius: 5px;
|
|
832
|
+
margin-bottom: 20px;
|
|
833
|
+
}
|
|
834
|
+
.flash.error {
|
|
835
|
+
background: #fee2e2;
|
|
836
|
+
color: #dc2626;
|
|
837
|
+
}
|
|
838
|
+
.flash.success {
|
|
839
|
+
background: #d1fae5;
|
|
840
|
+
color: #059669;
|
|
841
|
+
}
|
|
842
|
+
.feature-flag {
|
|
843
|
+
background: #fef3c7;
|
|
844
|
+
border: 2px dashed #f59e0b;
|
|
845
|
+
padding: 15px;
|
|
846
|
+
border-radius: 8px;
|
|
847
|
+
margin: 20px 0;
|
|
848
|
+
}
|
|
849
|
+
code {
|
|
850
|
+
background: #f3f4f6;
|
|
851
|
+
padding: 2px 6px;
|
|
852
|
+
border-radius: 3px;
|
|
853
|
+
font-family: monospace;
|
|
854
|
+
}
|
|
855
|
+
.count {
|
|
856
|
+
font-size: 48px;
|
|
857
|
+
font-weight: bold;
|
|
858
|
+
color: #1d4ed8;
|
|
859
|
+
text-align: center;
|
|
860
|
+
padding: 20px;
|
|
861
|
+
}
|
|
862
|
+
</style>
|
|
863
|
+
|
|
864
|
+
<!-- PostHog frontend tracking (posthog-js) -->
|
|
865
|
+
<script>
|
|
866
|
+
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug getPageViewId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
|
|
867
|
+
posthog.init('<%= ENV["POSTHOG_PROJECT_TOKEN"] %>', {
|
|
868
|
+
api_host: '<%= ENV.fetch("POSTHOG_HOST", "https://us.i.posthog.com") %>',
|
|
869
|
+
person_profiles: 'identified_only'
|
|
870
|
+
})
|
|
871
|
+
</script>
|
|
872
|
+
</head>
|
|
873
|
+
<body>
|
|
874
|
+
<% if current_user %>
|
|
875
|
+
<nav style="display: flex; align-items: center;">
|
|
876
|
+
<a href="<%= dashboard_path %>">Dashboard</a>
|
|
877
|
+
<a href="<%= burrito_path %>">Burrito</a>
|
|
878
|
+
<a href="<%= profile_path %>">Profile</a>
|
|
879
|
+
<%= button_to 'Logout (' + current_user.email + ')', logout_path, method: :delete, form: { style: 'margin-left: auto;' }, style: 'background: transparent; border: none; color: white; cursor: pointer; font-size: inherit; padding: 0;' %>
|
|
880
|
+
</nav>
|
|
881
|
+
<% end %>
|
|
882
|
+
|
|
883
|
+
<div class="container">
|
|
884
|
+
<% if flash[:error] %>
|
|
885
|
+
<div class="flash error"><%= flash[:error] %></div>
|
|
886
|
+
<% end %>
|
|
887
|
+
<% if flash[:notice] %>
|
|
888
|
+
<div class="flash success"><%= flash[:notice] %></div>
|
|
889
|
+
<% end %>
|
|
890
|
+
|
|
891
|
+
<%= yield %>
|
|
892
|
+
</div>
|
|
893
|
+
|
|
894
|
+
<%= yield :scripts %>
|
|
895
|
+
</body>
|
|
896
|
+
</html>
|
|
897
|
+
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
---
|
|
901
|
+
|
|
902
|
+
## app/views/profiles/show.html.erb
|
|
903
|
+
|
|
904
|
+
```erb
|
|
905
|
+
<% content_for(:title) { 'Profile - PostHog Rails example' } %>
|
|
906
|
+
|
|
907
|
+
<div class="card">
|
|
908
|
+
<h1>Profile</h1>
|
|
909
|
+
<p>This page demonstrates error tracking with PostHog and <code>posthog-rails</code>.</p>
|
|
910
|
+
</div>
|
|
911
|
+
|
|
912
|
+
<div class="card">
|
|
913
|
+
<h2>User information</h2>
|
|
914
|
+
<table style="width: 100%; border-collapse: collapse;">
|
|
915
|
+
<tr>
|
|
916
|
+
<td style="padding: 10px; border-bottom: 1px solid #eee;"><strong>Email:</strong></td>
|
|
917
|
+
<td style="padding: 10px; border-bottom: 1px solid #eee;"><%= current_user.email %></td>
|
|
918
|
+
</tr>
|
|
919
|
+
<tr>
|
|
920
|
+
<td style="padding: 10px; border-bottom: 1px solid #eee;"><strong>Date Joined:</strong></td>
|
|
921
|
+
<td style="padding: 10px; border-bottom: 1px solid #eee;"><%= current_user.created_at %></td>
|
|
922
|
+
</tr>
|
|
923
|
+
<tr>
|
|
924
|
+
<td style="padding: 10px;"><strong>Staff Status:</strong></td>
|
|
925
|
+
<td style="padding: 10px;"><%= current_user.is_staff ? 'Yes' : 'No' %></td>
|
|
926
|
+
</tr>
|
|
927
|
+
</table>
|
|
928
|
+
</div>
|
|
929
|
+
|
|
930
|
+
<div class="card">
|
|
931
|
+
<h2>Error tracking demo</h2>
|
|
932
|
+
<p>Click the buttons below to trigger different types of errors and see how PostHog captures them.</p>
|
|
933
|
+
|
|
934
|
+
<div style="margin-top: 20px;">
|
|
935
|
+
<button class="danger" onclick="triggerError('manual')">
|
|
936
|
+
Manual capture_exception
|
|
937
|
+
</button>
|
|
938
|
+
<button class="danger" onclick="triggerError('rails')" style="margin-left: 10px;">
|
|
939
|
+
Rails.error.handle
|
|
940
|
+
</button>
|
|
941
|
+
</div>
|
|
942
|
+
|
|
943
|
+
<div id="error-result" style="margin-top: 20px; display: none;"></div>
|
|
944
|
+
</div>
|
|
945
|
+
|
|
946
|
+
<div class="card">
|
|
947
|
+
<h3>How error tracking works</h3>
|
|
948
|
+
<p><strong>Auto-capture (no code needed):</strong></p>
|
|
949
|
+
<pre style="background: #f3f4f6; padding: 15px; border-radius: 5px; overflow-x: auto;"><code># config/initializers/posthog.rb
|
|
950
|
+
PostHog::Rails.configure do |config|
|
|
951
|
+
config.auto_capture_exceptions = true
|
|
952
|
+
config.capture_user_context = true
|
|
953
|
+
end
|
|
954
|
+
# That's it! Unhandled exceptions are captured automatically.</code></pre>
|
|
955
|
+
|
|
956
|
+
<p style="margin-top: 15px;"><strong>Manual capture:</strong></p>
|
|
957
|
+
<pre style="background: #f3f4f6; padding: 15px; border-radius: 5px; overflow-x: auto;"><code>begin
|
|
958
|
+
risky_operation
|
|
959
|
+
rescue => e
|
|
960
|
+
PostHog.capture_exception(e, user.posthog_distinct_id)
|
|
961
|
+
end</code></pre>
|
|
962
|
+
|
|
963
|
+
<p style="margin-top: 15px;"><strong>Rails.error integration:</strong></p>
|
|
964
|
+
<pre style="background: #f3f4f6; padding: 15px; border-radius: 5px; overflow-x: auto;"><code># posthog-rails subscribes to Rails.error automatically
|
|
965
|
+
Rails.error.handle(context: { user_id: user.id }) do
|
|
966
|
+
risky_operation
|
|
967
|
+
end</code></pre>
|
|
968
|
+
</div>
|
|
969
|
+
|
|
970
|
+
<% content_for :scripts do %>
|
|
971
|
+
<script>
|
|
972
|
+
async function triggerError(type) {
|
|
973
|
+
const resultDiv = document.getElementById('error-result');
|
|
974
|
+
const url = type === 'rails' ? '/api/test-rails-error' : '/api/test-error';
|
|
975
|
+
|
|
976
|
+
try {
|
|
977
|
+
const response = await fetch(url, {
|
|
978
|
+
method: 'POST',
|
|
979
|
+
headers: {
|
|
980
|
+
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content,
|
|
981
|
+
'Content-Type': 'application/json',
|
|
982
|
+
},
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
const data = await response.json();
|
|
986
|
+
|
|
987
|
+
resultDiv.style.display = 'block';
|
|
988
|
+
if (data.success) {
|
|
989
|
+
resultDiv.innerHTML = '<div class="flash success">' + data.message + '</div>';
|
|
990
|
+
} else {
|
|
991
|
+
resultDiv.innerHTML = '<div class="flash error"><strong>Error captured:</strong> ' + data.error + '<br><small>' + data.message + '</small></div>';
|
|
992
|
+
}
|
|
993
|
+
} catch (error) {
|
|
994
|
+
resultDiv.style.display = 'block';
|
|
995
|
+
resultDiv.innerHTML = '<div class="flash error">Request failed: ' + error + '</div>';
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
</script>
|
|
999
|
+
<% end %>
|
|
1000
|
+
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
---
|
|
1004
|
+
|
|
1005
|
+
## app/views/registrations/new.html.erb
|
|
1006
|
+
|
|
1007
|
+
```erb
|
|
1008
|
+
<% content_for(:title) { 'Sign Up - PostHog Rails example' } %>
|
|
1009
|
+
|
|
1010
|
+
<div class="card">
|
|
1011
|
+
<h1>Sign Up</h1>
|
|
1012
|
+
<p>Create an account to see PostHog analytics in action.</p>
|
|
1013
|
+
|
|
1014
|
+
<form action="<%= signup_path %>" method="post" style="margin-top: 20px;">
|
|
1015
|
+
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
|
|
1016
|
+
<input type="email" name="email" placeholder="Email" required>
|
|
1017
|
+
<input type="password" name="password" placeholder="Password" required>
|
|
1018
|
+
<input type="password" name="password_confirmation" placeholder="Confirm Password" required>
|
|
1019
|
+
<button type="submit">Sign Up</button>
|
|
1020
|
+
</form>
|
|
1021
|
+
|
|
1022
|
+
<p style="margin-top: 15px; color: #666; font-size: 14px;">
|
|
1023
|
+
Already have an account? <a href="<%= login_path %>">Login</a>
|
|
1024
|
+
</p>
|
|
1025
|
+
</div>
|
|
1026
|
+
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
---
|
|
1030
|
+
|
|
1031
|
+
## app/views/sessions/new.html.erb
|
|
1032
|
+
|
|
1033
|
+
```erb
|
|
1034
|
+
<% content_for(:title) { 'Login - PostHog Rails example' } %>
|
|
1035
|
+
|
|
1036
|
+
<div class="card">
|
|
1037
|
+
<h1>PostHog Rails example</h1>
|
|
1038
|
+
<p>Welcome! This example demonstrates PostHog integration with Ruby on Rails, including automatic error tracking via <code>posthog-rails</code>.</p>
|
|
1039
|
+
</div>
|
|
1040
|
+
|
|
1041
|
+
<div class="card">
|
|
1042
|
+
<h2>Login</h2>
|
|
1043
|
+
<p>Login to see PostHog analytics in action.</p>
|
|
1044
|
+
|
|
1045
|
+
<form action="<%= login_path %>" method="post" style="margin-top: 20px;">
|
|
1046
|
+
<%= hidden_field_tag :authenticity_token, form_authenticity_token %>
|
|
1047
|
+
<input type="email" name="email" placeholder="Email" required>
|
|
1048
|
+
<input type="password" name="password" placeholder="Password" required>
|
|
1049
|
+
<button type="submit">Login</button>
|
|
1050
|
+
</form>
|
|
1051
|
+
|
|
1052
|
+
<p style="margin-top: 15px; color: #666; font-size: 14px;">
|
|
1053
|
+
Don't have an account? <a href="<%= signup_path %>">Sign up</a><br>
|
|
1054
|
+
Tip: Run <code>bin/rails db:seed</code> to create admin@example.com / admin
|
|
1055
|
+
</p>
|
|
1056
|
+
</div>
|
|
1057
|
+
|
|
1058
|
+
<div class="card">
|
|
1059
|
+
<h3>What this example demonstrates</h3>
|
|
1060
|
+
<ul style="padding-left: 20px;">
|
|
1061
|
+
<li><strong>User identification</strong> — Users are identified with <code>PostHog.identify</code> on login</li>
|
|
1062
|
+
<li><strong>Event tracking</strong> — Custom events captured with <code>PostHog.capture</code></li>
|
|
1063
|
+
<li><strong>Feature flags</strong> — Conditional features with <code>PostHog.is_feature_enabled</code></li>
|
|
1064
|
+
<li><strong>Error tracking (auto)</strong> — Unhandled exceptions captured automatically by <code>posthog-rails</code></li>
|
|
1065
|
+
<li><strong>Error tracking (manual)</strong> — Handled errors captured with <code>PostHog.capture_exception</code></li>
|
|
1066
|
+
<li><strong>ActiveJob instrumentation</strong> — Background job failures captured automatically</li>
|
|
1067
|
+
<li><strong>Rails.error integration</strong> — Rails 7+ error reporting captured by <code>posthog-rails</code></li>
|
|
1068
|
+
<li><strong>Frontend tracking</strong> — posthog-js captures pageviews and session replay</li>
|
|
1069
|
+
</ul>
|
|
1070
|
+
</div>
|
|
1071
|
+
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
---
|
|
1075
|
+
|
|
1076
|
+
## config.ru
|
|
1077
|
+
|
|
1078
|
+
```ru
|
|
1079
|
+
require_relative 'config/environment'
|
|
1080
|
+
run Rails.application
|
|
1081
|
+
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
---
|
|
1085
|
+
|
|
1086
|
+
## config/application.rb
|
|
1087
|
+
|
|
1088
|
+
```rb
|
|
1089
|
+
require_relative 'boot'
|
|
1090
|
+
require 'rails/all'
|
|
1091
|
+
|
|
1092
|
+
Bundler.require(*Rails.groups)
|
|
1093
|
+
|
|
1094
|
+
module PosthogExample
|
|
1095
|
+
class Application < Rails::Application
|
|
1096
|
+
config.load_defaults 7.1
|
|
1097
|
+
|
|
1098
|
+
# Use SQLite for all stores
|
|
1099
|
+
config.active_job.queue_adapter = :async
|
|
1100
|
+
end
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
---
|
|
1106
|
+
|
|
1107
|
+
## config/boot.rb
|
|
1108
|
+
|
|
1109
|
+
```rb
|
|
1110
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
|
1111
|
+
|
|
1112
|
+
require 'bundler/setup'
|
|
1113
|
+
|
|
1114
|
+
```
|
|
1115
|
+
|
|
1116
|
+
---
|
|
1117
|
+
|
|
1118
|
+
## config/environment.rb
|
|
1119
|
+
|
|
1120
|
+
```rb
|
|
1121
|
+
require_relative 'application'
|
|
1122
|
+
Rails.application.initialize!
|
|
1123
|
+
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
---
|
|
1127
|
+
|
|
1128
|
+
## config/environments/development.rb
|
|
1129
|
+
|
|
1130
|
+
```rb
|
|
1131
|
+
require 'active_support/core_ext/integer/time'
|
|
1132
|
+
|
|
1133
|
+
Rails.application.configure do
|
|
1134
|
+
config.enable_reloading = true
|
|
1135
|
+
config.eager_load = false
|
|
1136
|
+
config.consider_all_requests_local = true
|
|
1137
|
+
config.server_timing = true
|
|
1138
|
+
|
|
1139
|
+
# Secret key for development (not used in production)
|
|
1140
|
+
config.secret_key_base = 'dev-secret-key-for-posthog-example-only'
|
|
1141
|
+
|
|
1142
|
+
config.action_controller.perform_caching = false
|
|
1143
|
+
config.cache_store = :memory_store
|
|
1144
|
+
|
|
1145
|
+
config.active_support.deprecation = :log
|
|
1146
|
+
config.active_support.disallowed_deprecation = :raise
|
|
1147
|
+
config.active_support.disallowed_deprecation_warnings = []
|
|
1148
|
+
|
|
1149
|
+
config.active_record.migration_error = :page_load
|
|
1150
|
+
config.active_record.verbose_query_logs = true
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
---
|
|
1156
|
+
|
|
1157
|
+
## config/initializers/posthog.rb
|
|
1158
|
+
|
|
1159
|
+
```rb
|
|
1160
|
+
# PostHog configuration with posthog-rails auto-instrumentation
|
|
1161
|
+
#
|
|
1162
|
+
# The posthog-rails gem provides:
|
|
1163
|
+
# - Automatic exception capture for unhandled controller errors
|
|
1164
|
+
# - ActiveJob instrumentation for background job failures
|
|
1165
|
+
# - User context detection from current_user
|
|
1166
|
+
# - Rails.error integration for rescued exceptions
|
|
1167
|
+
PostHog.init do |config|
|
|
1168
|
+
config.api_key = ENV.fetch('POSTHOG_PROJECT_TOKEN', nil)
|
|
1169
|
+
config.host = ENV.fetch('POSTHOG_HOST', 'https://us.i.posthog.com')
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
PostHog::Rails.configure do |config|
|
|
1173
|
+
# Auto-capture unhandled exceptions in controllers
|
|
1174
|
+
config.auto_capture_exceptions = true
|
|
1175
|
+
|
|
1176
|
+
# Also capture exceptions that Rails rescues (e.g. ActiveRecord::RecordNotFound)
|
|
1177
|
+
config.report_rescued_exceptions = true
|
|
1178
|
+
|
|
1179
|
+
# Auto-instrument ActiveJob failures
|
|
1180
|
+
config.auto_instrument_active_job = true
|
|
1181
|
+
|
|
1182
|
+
# Automatically associate errors with the current user
|
|
1183
|
+
config.capture_user_context = true
|
|
1184
|
+
config.current_user_method = :current_user
|
|
1185
|
+
config.user_id_method = :posthog_distinct_id
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
```
|
|
1190
|
+
|
|
1191
|
+
---
|
|
1192
|
+
|
|
1193
|
+
## config/routes.rb
|
|
1194
|
+
|
|
1195
|
+
```rb
|
|
1196
|
+
Rails.application.routes.draw do
|
|
1197
|
+
# Auth
|
|
1198
|
+
get 'login', to: 'sessions#new'
|
|
1199
|
+
post 'login', to: 'sessions#create'
|
|
1200
|
+
delete 'logout', to: 'sessions#destroy'
|
|
1201
|
+
|
|
1202
|
+
get 'signup', to: 'registrations#new'
|
|
1203
|
+
post 'signup', to: 'registrations#create'
|
|
1204
|
+
|
|
1205
|
+
# App
|
|
1206
|
+
get 'dashboard', to: 'dashboard#show'
|
|
1207
|
+
get 'burrito', to: 'burritos#show'
|
|
1208
|
+
post 'api/burrito/consider', to: 'burritos#consider'
|
|
1209
|
+
get 'profile', to: 'profiles#show'
|
|
1210
|
+
|
|
1211
|
+
# Error tracking demos
|
|
1212
|
+
post 'api/test-error', to: 'errors#test'
|
|
1213
|
+
post 'api/test-rails-error', to: 'errors#test_rails_error'
|
|
1214
|
+
|
|
1215
|
+
# Background job demo
|
|
1216
|
+
post 'api/test-job', to: 'dashboard#enqueue_test_job'
|
|
1217
|
+
|
|
1218
|
+
root 'sessions#new'
|
|
1219
|
+
end
|
|
1220
|
+
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
---
|
|
1224
|
+
|
|
1225
|
+
## db/migrate/20240101000000_create_users.rb
|
|
1226
|
+
|
|
1227
|
+
```rb
|
|
1228
|
+
class CreateUsers < ActiveRecord::Migration[7.1]
|
|
1229
|
+
def change
|
|
1230
|
+
create_table :users do |t|
|
|
1231
|
+
t.string :email, null: false
|
|
1232
|
+
t.string :password_digest, null: false
|
|
1233
|
+
t.boolean :is_staff, default: false
|
|
1234
|
+
|
|
1235
|
+
t.timestamps
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
add_index :users, :email, unique: true
|
|
1239
|
+
end
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
```
|
|
1243
|
+
|
|
1244
|
+
---
|
|
1245
|
+
|
|
1246
|
+
## db/schema.rb
|
|
1247
|
+
|
|
1248
|
+
```rb
|
|
1249
|
+
# This file is auto-generated from the current state of the database. Instead
|
|
1250
|
+
# of editing this file, please use the migrations feature of Active Record to
|
|
1251
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
|
1252
|
+
#
|
|
1253
|
+
# This file is the source Rails uses to define your schema when running `bin/rails
|
|
1254
|
+
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
|
1255
|
+
# be faster and is potentially less error prone than running all of your
|
|
1256
|
+
# migrations from scratch. Old migrations may fail to apply correctly if those
|
|
1257
|
+
# migrations use external dependencies or application code.
|
|
1258
|
+
#
|
|
1259
|
+
# It's strongly recommended that you check this file into your version control system.
|
|
1260
|
+
|
|
1261
|
+
ActiveRecord::Schema[7.2].define(version: 2024_01_01_000000) do
|
|
1262
|
+
create_table "users", force: :cascade do |t|
|
|
1263
|
+
t.string "email", null: false
|
|
1264
|
+
t.string "password_digest", null: false
|
|
1265
|
+
t.boolean "is_staff", default: false
|
|
1266
|
+
t.datetime "created_at", null: false
|
|
1267
|
+
t.datetime "updated_at", null: false
|
|
1268
|
+
t.index ["email"], name: "index_users_on_email", unique: true
|
|
1269
|
+
end
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
```
|
|
1273
|
+
|
|
1274
|
+
---
|
|
1275
|
+
|
|
1276
|
+
## db/seeds.rb
|
|
1277
|
+
|
|
1278
|
+
```rb
|
|
1279
|
+
# Create a default admin user for testing
|
|
1280
|
+
User.find_or_create_by!(email: 'admin@example.com') do |user|
|
|
1281
|
+
user.password = 'admin'
|
|
1282
|
+
user.password_confirmation = 'admin'
|
|
1283
|
+
user.is_staff = true
|
|
1284
|
+
end
|
|
1285
|
+
|
|
1286
|
+
puts 'Seed data created: admin@example.com / admin'
|
|
1287
|
+
|
|
1288
|
+
```
|
|
1289
|
+
|
|
1290
|
+
---
|
|
1291
|
+
|
|
1292
|
+
## Gemfile
|
|
1293
|
+
|
|
1294
|
+
```
|
|
1295
|
+
source 'https://rubygems.org'
|
|
1296
|
+
|
|
1297
|
+
gem 'rails', '~> 7.1'
|
|
1298
|
+
gem 'sqlite3', '~> 1.7'
|
|
1299
|
+
gem 'puma', '~> 6.0'
|
|
1300
|
+
gem 'bcrypt', '~> 3.1'
|
|
1301
|
+
gem 'dotenv-rails', '~> 3.0'
|
|
1302
|
+
|
|
1303
|
+
# PostHog
|
|
1304
|
+
gem 'posthog-ruby', '~> 3.0'
|
|
1305
|
+
gem 'posthog-rails'
|
|
1306
|
+
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
---
|
|
1310
|
+
|
|
1311
|
+
## Rakefile
|
|
1312
|
+
|
|
1313
|
+
```
|
|
1314
|
+
require_relative 'config/application'
|
|
1315
|
+
Rails.application.load_tasks
|
|
1316
|
+
|
|
1317
|
+
```
|
|
1318
|
+
|
|
1319
|
+
---
|
|
1320
|
+
|