appiq-solution 1.3.3 → 1.4.3
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/#Tools/APPIQ-METHOD/.bmad-config.json +13 -0
- package/#Tools/APPIQ-METHOD/.cursor/commands/analyze.md +27 -0
- package/#Tools/APPIQ-METHOD/.cursor/commands/appiq.md +27 -0
- package/#Tools/APPIQ-METHOD/.cursor/commands/help.md +27 -0
- package/#Tools/APPIQ-METHOD/.cursor/commands/story.md +27 -0
- package/#Tools/APPIQ-METHOD/CHANGELOG.md +119 -173
- package/#Tools/APPIQ-METHOD/DEVELOPMENT_GUIDE.md +855 -0
- package/#Tools/APPIQ-METHOD/NPM-README.md +138 -0
- package/#Tools/APPIQ-METHOD/SMART_WORKFLOW_GUIDE.md +401 -0
- package/#Tools/APPIQ-METHOD/activate-appiq.js +81 -0
- package/#Tools/APPIQ-METHOD/appiq-solution/README.md +226 -0
- package/#Tools/APPIQ-METHOD/bmad-core/agent-teams/team-flutter-mobile.yaml +114 -0
- package/#Tools/APPIQ-METHOD/bmad-core/agent-teams/team-fullstack.yaml +11 -1
- package/#Tools/APPIQ-METHOD/bmad-core/agents/analyst.md +7 -3
- package/#Tools/APPIQ-METHOD/bmad-core/agents/architect.md +6 -0
- package/#Tools/APPIQ-METHOD/bmad-core/agents/bmad-orchestrator.md +0 -84
- package/#Tools/APPIQ-METHOD/bmad-core/agents/bmad-smart-launcher.md +170 -0
- package/#Tools/APPIQ-METHOD/bmad-core/agents/dev.md +31 -12
- package/#Tools/APPIQ-METHOD/bmad-core/agents/pm.md +10 -4
- package/#Tools/APPIQ-METHOD/bmad-core/agents/qa.md +17 -0
- package/#Tools/APPIQ-METHOD/bmad-core/agents/sm.md +8 -3
- package/#Tools/APPIQ-METHOD/bmad-core/agents/ux-expert.md +8 -3
- package/#Tools/APPIQ-METHOD/bmad-core/bmad-core/user-guide.md +0 -0
- package/#Tools/APPIQ-METHOD/bmad-core/checklists/security-validation-checklist.md +332 -0
- package/#Tools/APPIQ-METHOD/bmad-core/data/backend-services-integration.md +686 -0
- package/#Tools/APPIQ-METHOD/bmad-core/data/shadcn-ui-integration.md +388 -0
- package/#Tools/APPIQ-METHOD/bmad-core/data/technical-preferences.md +147 -1
- package/#Tools/APPIQ-METHOD/bmad-core/enhanced-ide-development-workflow.md +43 -0
- package/#Tools/APPIQ-METHOD/bmad-core/tasks/create-flutter-story.md +197 -0
- package/#Tools/APPIQ-METHOD/bmad-core/tasks/intelligent-epic-creation.md +234 -0
- package/#Tools/APPIQ-METHOD/bmad-core/tasks/smart-project-analysis.md +289 -0
- package/#Tools/APPIQ-METHOD/bmad-core/templates/flutter-mobile-prd-tmpl.yaml +330 -0
- package/#Tools/APPIQ-METHOD/bmad-core/templates/flutter-story-tmpl.yaml +376 -0
- package/#Tools/APPIQ-METHOD/bmad-core/templates/flutter-ui-spec-tmpl.yaml +415 -0
- package/#Tools/APPIQ-METHOD/bmad-core/templates/fullstack-architecture-tmpl.yaml +12 -5
- package/#Tools/APPIQ-METHOD/bmad-core/user-guide.md +10 -9
- package/#Tools/APPIQ-METHOD/bmad-core/workflows/brownfield-fullstack.yaml +15 -1
- package/#Tools/APPIQ-METHOD/bmad-core/workflows/greenfield-fullstack.yaml +49 -5
- package/#Tools/APPIQ-METHOD/bmad-core/working-in-the-brownfield.md +56 -44
- package/#Tools/APPIQ-METHOD/commands/README.md +28 -0
- package/#Tools/APPIQ-METHOD/commands/analyze.md +27 -0
- package/#Tools/APPIQ-METHOD/commands/appiq.md +27 -0
- package/#Tools/APPIQ-METHOD/commands/help.md +27 -0
- package/#Tools/APPIQ-METHOD/commands/story.md +27 -0
- package/#Tools/APPIQ-METHOD/dist/agents/bmad-orchestrator.txt +0 -111
- package/#Tools/APPIQ-METHOD/dist/agents/pm.txt +2 -0
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-2d-phaser-game-dev/teams/phaser-2d-nodejs-game-team.txt +0 -111
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-2d-unity-game-dev/teams/unity-2d-game-team.txt +0 -111
- package/#Tools/APPIQ-METHOD/dist/teams/team-all.txt +2 -111
- package/#Tools/APPIQ-METHOD/dist/teams/team-fullstack.txt +2 -111
- package/#Tools/APPIQ-METHOD/dist/teams/team-ide-minimal.txt +0 -111
- package/#Tools/APPIQ-METHOD/dist/teams/team-no-ui.txt +2 -111
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +1 -1
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-2d-unity-game-dev/config.yaml +1 -1
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agent-teams/flutter-mobile-team.yaml +23 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agents/flutter-cubit-agent.md +133 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agents/flutter-data-agent.md +160 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agents/flutter-domain-agent.md +153 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agents/flutter-ui-agent.md +122 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/agents/shared-components-agent.md +161 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/checklists/flutter-story-dod-checklist.md +194 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/config.yaml +41 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/data/flutter-development-guidelines.md +551 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/templates/flutter-mobile-architecture-tmpl.yaml +530 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-flutter-mobile-dev/workflows/flutter-ui-first-development.yaml +220 -0
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-infrastructure-devops/config.yaml +1 -1
- package/#Tools/APPIQ-METHOD/install-appiq.sh +41 -0
- package/#Tools/APPIQ-METHOD/package-lock.json +631 -0
- package/#Tools/APPIQ-METHOD/package.json +20 -69
- package/#Tools/APPIQ-METHOD/tasks/todo.md +275 -0
- package/#Tools/APPIQ-METHOD/tools/appiq-installer.js +2714 -0
- package/#Tools/APPIQ-METHOD/tools/bmad-npx-wrapper.js +5 -7
- package/#Tools/APPIQ-METHOD/tools/cli.js +3 -3
- package/#Tools/APPIQ-METHOD/tools/epic-solution-installer.js +538 -0
- package/#Tools/APPIQ-METHOD/tools/flattener/main.js +570 -0
- package/#Tools/APPIQ-METHOD/tools/installer/bin/bmad.js +15 -14
- package/#Tools/APPIQ-METHOD/tools/installer/lib/installer.js +28 -2
- package/#Tools/APPIQ-METHOD/tools/installer/package-lock.json +906 -0
- package/#Tools/APPIQ-METHOD/tools/installer/package.json +1 -1
- package/#Tools/APPIQ-METHOD/tools/setup-ide-commands.js +345 -0
- package/#Tools/APPIQ-METHOD/tools/smart-installer.js +589 -0
- package/package.json +20 -69
- package/tools/appiq-installer.js +2714 -0
- package/tools/bmad-npx-wrapper.js +5 -7
- package/tools/cli.js +3 -3
- package/tools/epic-solution-installer.js +538 -0
- package/tools/flattener/main.js +570 -0
- package/tools/installer/bin/bmad.js +15 -14
- package/tools/installer/lib/installer.js +28 -2
- package/tools/installer/package-lock.json +89 -89
- package/tools/installer/package.json +1 -1
- package/tools/setup-ide-commands.js +345 -0
- package/tools/smart-installer.js +589 -0
- package/#Tools/APPIQ-METHOD/appiq_start.md +0 -232
- package/#Tools/APPIQ-METHOD/deployment/DEPLOYMENT_GUIDE.md +0 -426
- package/#Tools/APPIQ-METHOD/deployment/GITHUB_RELEASE_GUIDE.md +0 -326
- package/#Tools/APPIQ-METHOD/deployment/README.md +0 -331
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agent-teams/team-all.yaml +0 -14
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agent-teams/team-fullstack.yaml +0 -18
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agent-teams/team-ide-minimal.yaml +0 -10
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agent-teams/team-no-ui.yaml +0 -13
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/analyst.md +0 -81
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/architect.md +0 -84
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/bmad-master.md +0 -108
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/bmad-orchestrator.md +0 -234
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/dev.md +0 -76
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/pm.md +0 -79
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/po.md +0 -76
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/qa.md +0 -69
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/sm.md +0 -62
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/agents/ux-expert.md +0 -66
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/architect-checklist.md +0 -443
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/change-checklist.md +0 -182
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/pm-checklist.md +0 -375
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/po-master-checklist.md +0 -441
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/story-dod-checklist.md +0 -101
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/checklists/story-draft-checklist.md +0 -156
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/data/bmad-kb.md +0 -803
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/data/brainstorming-techniques.md +0 -36
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/data/elicitation-methods.md +0 -134
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/data/technical-preferences.md +0 -3
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/advanced-elicitation.md +0 -117
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/brownfield-create-epic.md +0 -160
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/brownfield-create-story.md +0 -147
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/correct-course.md +0 -70
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/create-brownfield-story.md +0 -304
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/create-deep-research-prompt.md +0 -289
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/create-next-story.md +0 -112
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/document-project.md +0 -341
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/facilitate-brainstorming-session.md +0 -136
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/generate-ai-frontend-prompt.md +0 -51
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/index-docs.md +0 -179
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/kb-mode-interaction.md +0 -75
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/review-story.md +0 -145
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/shard-doc.md +0 -187
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/tasks/validate-next-story.md +0 -134
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/architecture-tmpl.yaml +0 -650
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/brainstorming-output-tmpl.yaml +0 -156
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/brownfield-architecture-tmpl.yaml +0 -476
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/brownfield-prd-tmpl.yaml +0 -280
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/competitor-analysis-tmpl.yaml +0 -293
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/front-end-architecture-tmpl.yaml +0 -206
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/front-end-spec-tmpl.yaml +0 -349
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/fullstack-architecture-tmpl.yaml +0 -805
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/market-research-tmpl.yaml +0 -252
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/prd-tmpl.yaml +0 -202
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/project-brief-tmpl.yaml +0 -221
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/templates/story-tmpl.yaml +0 -137
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/user-guide.md +0 -250
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/brownfield-fullstack.yaml +0 -297
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/brownfield-service.yaml +0 -187
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/brownfield-ui.yaml +0 -197
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/greenfield-fullstack.yaml +0 -240
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/greenfield-service.yaml +0 -206
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/workflows/greenfield-ui.yaml +0 -235
- package/#Tools/APPIQ-METHOD/deployment/build/bmad-core/working-in-the-brownfield.md +0 -361
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/README.md +0 -3
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/agent-teams/phaser-2d-nodejs-game-team.yaml +0 -13
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/agents/game-designer.md +0 -71
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/agents/game-developer.md +0 -78
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/agents/game-sm.md +0 -64
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-design-checklist.md +0 -201
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/checklists/game-story-dod-checklist.md +0 -160
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/config.yaml +0 -8
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/data/bmad-kb.md +0 -254
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/data/development-guidelines.md +0 -651
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/tasks/advanced-elicitation.md +0 -111
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/tasks/create-game-story.md +0 -216
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/tasks/game-design-brainstorming.md +0 -308
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/templates/game-architecture-tmpl.yaml +0 -613
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/templates/game-brief-tmpl.yaml +0 -356
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/templates/game-design-doc-tmpl.yaml +0 -343
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/templates/game-story-tmpl.yaml +0 -253
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/templates/level-design-doc-tmpl.yaml +0 -484
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-dev-greenfield.yaml +0 -183
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-phaser-game-dev/workflows/game-prototype.yaml +0 -175
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/agent-teams/unity-2d-game-team.yaml +0 -14
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/agents/game-architect.md +0 -80
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/agents/game-designer.md +0 -77
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/agents/game-developer.md +0 -78
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/agents/game-sm.md +0 -65
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/checklists/game-architect-checklist.md +0 -396
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/checklists/game-change-checklist.md +0 -203
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/checklists/game-design-checklist.md +0 -201
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/checklists/game-story-dod-checklist.md +0 -132
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/config.yaml +0 -6
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/data/bmad-kb.md +0 -776
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/data/development-guidelines.md +0 -590
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/tasks/advanced-elicitation.md +0 -111
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/tasks/correct-course-game.md +0 -151
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/tasks/create-game-story.md +0 -184
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/tasks/game-design-brainstorming.md +0 -308
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/tasks/validate-game-story.md +0 -200
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/templates/game-architecture-tmpl.yaml +0 -1030
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/templates/game-brief-tmpl.yaml +0 -356
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/templates/game-design-doc-tmpl.yaml +0 -705
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/templates/game-story-tmpl.yaml +0 -256
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/templates/level-design-doc-tmpl.yaml +0 -484
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/workflows/game-dev-greenfield.yaml +0 -183
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-2d-unity-game-dev/workflows/game-prototype.yaml +0 -175
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/README.md +0 -147
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/agents/infra-devops-platform.md +0 -71
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/checklists/infrastructure-checklist.md +0 -484
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/config.yaml +0 -9
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/data/bmad-kb.md +0 -308
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/tasks/review-infrastructure.md +0 -160
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/tasks/validate-infrastructure.md +0 -154
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-architecture-tmpl.yaml +0 -424
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-infrastructure-devops/templates/infrastructure-platform-from-arch-tmpl.yaml +0 -629
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-cross-platform.yaml +0 -22
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-flutter.yaml +0 -20
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-minimal.yaml +0 -13
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-react-native.yaml +0 -20
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-analytics.md +0 -1487
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-architect.md +0 -279
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-developer.md +0 -649
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-pm.md +0 -339
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-qa.md +0 -622
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-security.md +0 -1027
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/agents/mobile-ux-expert.md +0 -1451
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/checklists/mobile-development-checklist.md +0 -490
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/config.yaml +0 -54
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/data/bmad-kb.md +0 -292
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/data/flutter-development-guidelines.md +0 -483
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/tasks/existing-app-analysis.md +0 -645
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/tasks/platform-selection.md +0 -489
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/templates/mobile-architecture-tmpl.yaml +0 -437
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/templates/mobile-prd-tmpl.yaml +0 -408
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-app-development-init.yaml +0 -555
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-brownfield-flutter.yaml +0 -336
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-brownfield-react-native.yaml +0 -345
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-greenfield-flutter.yaml +0 -281
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-greenfield-react-native.yaml +0 -283
- package/#Tools/APPIQ-METHOD/deployment/build/expansion-packs/bmad-mobile-app-dev/workflows/mobile-platform-selection.yaml +0 -404
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/appiq.md +0 -273
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/ide-integrations/claude-appiq.md +0 -294
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/ide-integrations/cursor-appiq.md +0 -516
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/ide-integrations/universal-appiq.md +0 -448
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/ide-integrations/windsurf-appiq.md +0 -698
- package/#Tools/APPIQ-METHOD/deployment/build/slash-commands/start.md +0 -211
- package/#Tools/APPIQ-METHOD/deployment/build-release.sh +0 -449
- package/#Tools/APPIQ-METHOD/deployment/create-release.sh +0 -196
- package/#Tools/APPIQ-METHOD/deployment/dist/appiq_installer.sh +0 -678
- package/#Tools/APPIQ-METHOD/deployment/docs/main_prd.md +0 -36
- package/#Tools/APPIQ-METHOD/deployment/init_appiq.sh +0 -805
- package/#Tools/APPIQ-METHOD/deployment/init_appiq_v2.sh +0 -678
- package/#Tools/APPIQ-METHOD/deployment/installers/appiq-global.sh +0 -91
- package/#Tools/APPIQ-METHOD/deployment/installers/claude-integration.sh +0 -281
- package/#Tools/APPIQ-METHOD/deployment/installers/cursor-integration.sh +0 -257
- package/#Tools/APPIQ-METHOD/deployment/installers/terminal-integration.sh +0 -645
- package/#Tools/APPIQ-METHOD/deployment/installers/windsurf-integration.sh +0 -350
- package/#Tools/APPIQ-METHOD/deployment/package-v2.sh +0 -97
- package/#Tools/APPIQ-METHOD/deployment/package.sh +0 -363
- package/#Tools/APPIQ-METHOD/deployment/quick-install.sh +0 -57
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-analytics.txt +0 -1530
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-architect.txt +0 -322
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-developer.txt +0 -692
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-pm.txt +0 -382
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-qa.txt +0 -665
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-security.txt +0 -1070
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/agents/mobile-ux-expert.txt +0 -1494
- package/#Tools/APPIQ-METHOD/dist/expansion-packs/bmad-mobile-app-dev/teams/mobile-team-cross-platform.txt +0 -15613
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-cross-platform.yaml +0 -22
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-flutter.yaml +0 -20
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-minimal.yaml +0 -13
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agent-teams/mobile-team-react-native.yaml +0 -20
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-analytics.md +0 -1487
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-architect.md +0 -279
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-developer.md +0 -649
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-pm.md +0 -339
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-qa.md +0 -622
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-security.md +0 -1027
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/agents/mobile-ux-expert.md +0 -1451
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/checklists/mobile-development-checklist.md +0 -490
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/config.yaml +0 -54
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/data/bmad-kb.md +0 -292
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/data/flutter-development-guidelines.md +0 -483
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/tasks/existing-app-analysis.md +0 -645
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/tasks/platform-selection.md +0 -489
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/templates/mobile-architecture-tmpl.yaml +0 -437
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/templates/mobile-prd-tmpl.yaml +0 -408
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-app-development-init.yaml +0 -555
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-brownfield-flutter.yaml +0 -336
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-brownfield-react-native.yaml +0 -345
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-greenfield-flutter.yaml +0 -281
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-greenfield-react-native.yaml +0 -283
- package/#Tools/APPIQ-METHOD/expansion-packs/bmad-mobile-app-dev/workflows/mobile-platform-selection.yaml +0 -404
- package/#Tools/APPIQ-METHOD/package-bmad-backup.json +0 -78
- package/#Tools/APPIQ-METHOD/slash-commands/appiq.md +0 -273
- package/#Tools/APPIQ-METHOD/slash-commands/ide-integrations/claude-appiq.md +0 -294
- package/#Tools/APPIQ-METHOD/slash-commands/ide-integrations/cursor-appiq.md +0 -516
- package/#Tools/APPIQ-METHOD/slash-commands/ide-integrations/universal-appiq.md +0 -448
- package/#Tools/APPIQ-METHOD/slash-commands/ide-integrations/windsurf-appiq.md +0 -698
- package/#Tools/APPIQ-METHOD/slash-commands/start.md +0 -211
- /package/#Tools/APPIQ-METHOD/{deployment/build/bmad-core/core-config.yaml → bmad-core/core-config.yaml.bak} +0 -0
@@ -1,1487 +0,0 @@
|
|
1
|
-
---
|
2
|
-
role: Mobile Analytics Engineer
|
3
|
-
persona: Senior Mobile Analytics and Data Engineer
|
4
|
-
description: >-
|
5
|
-
Expert mobile analytics engineer specializing in Flutter and React Native applications.
|
6
|
-
Implements comprehensive analytics strategies, user behavior tracking, performance monitoring,
|
7
|
-
and business intelligence for mobile apps while ensuring privacy compliance.
|
8
|
-
|
9
|
-
dependencies:
|
10
|
-
templates:
|
11
|
-
- mobile-analytics-strategy-tmpl.yaml
|
12
|
-
- mobile-event-tracking-tmpl.yaml
|
13
|
-
tasks:
|
14
|
-
- mobile-analytics-implementation.md
|
15
|
-
- mobile-performance-monitoring.md
|
16
|
-
- mobile-user-behavior-analysis.md
|
17
|
-
data:
|
18
|
-
- bmad-kb.md
|
19
|
-
- mobile-analytics-guidelines.md
|
20
|
-
checklists:
|
21
|
-
- mobile-development-checklist.md
|
22
|
-
- mobile-analytics-checklist.md
|
23
|
-
|
24
|
-
startup_instructions: |
|
25
|
-
As the Mobile Analytics Engineer, I implement comprehensive analytics and monitoring
|
26
|
-
systems for mobile applications to drive data-driven decisions and optimize user experience.
|
27
|
-
|
28
|
-
My analytics expertise includes:
|
29
|
-
|
30
|
-
1. **User Behavior Analytics**
|
31
|
-
- User journey mapping and funnel analysis
|
32
|
-
- Feature usage tracking and adoption metrics
|
33
|
-
- User segmentation and cohort analysis
|
34
|
-
- A/B testing implementation and analysis
|
35
|
-
|
36
|
-
2. **Performance Monitoring**
|
37
|
-
- App performance metrics (launch time, crashes, ANRs)
|
38
|
-
- Network performance and API response monitoring
|
39
|
-
- Memory usage and battery consumption tracking
|
40
|
-
- Real-time performance alerting
|
41
|
-
|
42
|
-
3. **Business Intelligence**
|
43
|
-
- Revenue and conversion tracking
|
44
|
-
- User acquisition and retention metrics
|
45
|
-
- Engagement and satisfaction measurement
|
46
|
-
- Custom business KPI implementation
|
47
|
-
|
48
|
-
4. **Privacy-Compliant Implementation**
|
49
|
-
- GDPR and CCPA compliance
|
50
|
-
- User consent management
|
51
|
-
- Data anonymization and aggregation
|
52
|
-
- Privacy-preserving analytics techniques
|
53
|
-
|
54
|
-
Available commands:
|
55
|
-
- `*help` - Show analytics commands and mobile analytics guidance
|
56
|
-
- `*analytics-strategy` - Create comprehensive analytics strategy
|
57
|
-
- `*implement-tracking` - Implement event tracking and monitoring
|
58
|
-
- `*performance-monitoring` - Set up performance monitoring
|
59
|
-
- `*user-analysis` - Analyze user behavior and create reports
|
60
|
-
- `*privacy-compliance` - Ensure analytics privacy compliance
|
61
|
-
---
|
62
|
-
|
63
|
-
# Mobile Analytics Engineer Agent
|
64
|
-
|
65
|
-
I'm your Mobile Analytics Engineer, specializing in comprehensive analytics implementation for Flutter and React Native applications. I help you understand your users, optimize performance, and make data-driven decisions while maintaining privacy compliance.
|
66
|
-
|
67
|
-
## Mobile Analytics Strategy Framework
|
68
|
-
|
69
|
-
### Analytics Architecture Overview
|
70
|
-
|
71
|
-
```
|
72
|
-
Mobile Analytics Ecosystem:
|
73
|
-
├── Client-Side Analytics
|
74
|
-
│ ├── Event Tracking (user interactions, custom events)
|
75
|
-
│ ├── Performance Monitoring (crashes, ANRs, performance)
|
76
|
-
│ ├── User Journey Tracking (screens, flows, funnels)
|
77
|
-
│ └── Error Reporting (exceptions, network errors)
|
78
|
-
├── Server-Side Analytics
|
79
|
-
│ ├── API Performance Monitoring
|
80
|
-
│ ├── Business Logic Analytics
|
81
|
-
│ ├── Revenue and Conversion Tracking
|
82
|
-
│ └── Cross-Platform Data Aggregation
|
83
|
-
├── Real-Time Monitoring
|
84
|
-
│ ├── Live Performance Dashboards
|
85
|
-
│ ├── Alert Systems
|
86
|
-
│ ├── Anomaly Detection
|
87
|
-
│ └── Real-Time User Behavior
|
88
|
-
└── Privacy & Compliance
|
89
|
-
├── Consent Management
|
90
|
-
├── Data Anonymization
|
91
|
-
├── GDPR/CCPA Compliance
|
92
|
-
└── Data Retention Policies
|
93
|
-
```
|
94
|
-
|
95
|
-
### Flutter Analytics Implementation
|
96
|
-
|
97
|
-
**Flutter Analytics Service Architecture:**
|
98
|
-
```dart
|
99
|
-
// Comprehensive Analytics Service for Flutter
|
100
|
-
class FlutterAnalyticsService {
|
101
|
-
static final FlutterAnalyticsService _instance = FlutterAnalyticsService._internal();
|
102
|
-
factory FlutterAnalyticsService() => _instance;
|
103
|
-
FlutterAnalyticsService._internal();
|
104
|
-
|
105
|
-
late FirebaseAnalytics _firebaseAnalytics;
|
106
|
-
late Mixpanel _mixpanel;
|
107
|
-
late AmplitudeFlutter _amplitude;
|
108
|
-
bool _isInitialized = false;
|
109
|
-
bool _hasUserConsent = false;
|
110
|
-
|
111
|
-
// Initialize analytics with privacy compliance
|
112
|
-
Future<void> initialize({
|
113
|
-
required bool hasUserConsent,
|
114
|
-
Map<String, dynamic>? userProperties,
|
115
|
-
}) async {
|
116
|
-
_hasUserConsent = hasUserConsent;
|
117
|
-
|
118
|
-
if (!_hasUserConsent) {
|
119
|
-
AnalyticsLogger.info('Analytics initialized without user consent - limited tracking');
|
120
|
-
return;
|
121
|
-
}
|
122
|
-
|
123
|
-
try {
|
124
|
-
// Initialize Firebase Analytics
|
125
|
-
_firebaseAnalytics = FirebaseAnalytics.instance;
|
126
|
-
await _firebaseAnalytics.setAnalyticsCollectionEnabled(true);
|
127
|
-
|
128
|
-
// Initialize Mixpanel
|
129
|
-
_mixpanel = await Mixpanel.init(
|
130
|
-
'YOUR_MIXPANEL_TOKEN',
|
131
|
-
optOutTrackingDefault: false,
|
132
|
-
);
|
133
|
-
|
134
|
-
// Initialize Amplitude
|
135
|
-
_amplitude = AmplitudeFlutter('YOUR_AMPLITUDE_KEY');
|
136
|
-
await _amplitude.init();
|
137
|
-
|
138
|
-
// Set user properties if provided
|
139
|
-
if (userProperties != null) {
|
140
|
-
await setUserProperties(userProperties);
|
141
|
-
}
|
142
|
-
|
143
|
-
_isInitialized = true;
|
144
|
-
AnalyticsLogger.info('Analytics services initialized successfully');
|
145
|
-
} catch (e) {
|
146
|
-
AnalyticsLogger.error('Analytics initialization failed: $e');
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
// Track user events with context
|
151
|
-
Future<void> trackEvent({
|
152
|
-
required String eventName,
|
153
|
-
Map<String, dynamic>? parameters,
|
154
|
-
AnalyticsContext? context,
|
155
|
-
}) async {
|
156
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
157
|
-
|
158
|
-
try {
|
159
|
-
final enrichedParameters = _enrichEventParameters(parameters, context);
|
160
|
-
|
161
|
-
// Track with Firebase Analytics
|
162
|
-
await _firebaseAnalytics.logEvent(
|
163
|
-
name: _sanitizeEventName(eventName),
|
164
|
-
parameters: enrichedParameters,
|
165
|
-
);
|
166
|
-
|
167
|
-
// Track with Mixpanel
|
168
|
-
await _mixpanel.track(eventName, properties: enrichedParameters);
|
169
|
-
|
170
|
-
// Track with Amplitude
|
171
|
-
await _amplitude.logEvent(eventName, eventProperties: enrichedParameters);
|
172
|
-
|
173
|
-
AnalyticsLogger.debug('Event tracked: $eventName');
|
174
|
-
} catch (e) {
|
175
|
-
AnalyticsLogger.error('Event tracking failed: $e');
|
176
|
-
}
|
177
|
-
}
|
178
|
-
|
179
|
-
// Track screen views with navigation context
|
180
|
-
Future<void> trackScreenView({
|
181
|
-
required String screenName,
|
182
|
-
String? screenClass,
|
183
|
-
Map<String, dynamic>? parameters,
|
184
|
-
}) async {
|
185
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
186
|
-
|
187
|
-
try {
|
188
|
-
final screenParameters = {
|
189
|
-
'screen_name': screenName,
|
190
|
-
'screen_class': screenClass ?? screenName,
|
191
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
192
|
-
...?parameters,
|
193
|
-
};
|
194
|
-
|
195
|
-
// Firebase screen tracking
|
196
|
-
await _firebaseAnalytics.logScreenView(
|
197
|
-
screenName: screenName,
|
198
|
-
screenClass: screenClass,
|
199
|
-
parameters: screenParameters,
|
200
|
-
);
|
201
|
-
|
202
|
-
// Mixpanel screen tracking
|
203
|
-
await _mixpanel.track('Screen View', properties: screenParameters);
|
204
|
-
|
205
|
-
// Amplitude screen tracking
|
206
|
-
await _amplitude.logEvent('Screen View', eventProperties: screenParameters);
|
207
|
-
|
208
|
-
AnalyticsLogger.debug('Screen view tracked: $screenName');
|
209
|
-
} catch (e) {
|
210
|
-
AnalyticsLogger.error('Screen tracking failed: $e');
|
211
|
-
}
|
212
|
-
}
|
213
|
-
|
214
|
-
// User journey and funnel tracking
|
215
|
-
Future<void> trackUserJourney({
|
216
|
-
required String journeyName,
|
217
|
-
required String stepName,
|
218
|
-
Map<String, dynamic>? stepData,
|
219
|
-
}) async {
|
220
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
221
|
-
|
222
|
-
try {
|
223
|
-
final journeyData = {
|
224
|
-
'journey_name': journeyName,
|
225
|
-
'step_name': stepName,
|
226
|
-
'step_timestamp': DateTime.now().millisecondsSinceEpoch,
|
227
|
-
'step_data': stepData ?? {},
|
228
|
-
};
|
229
|
-
|
230
|
-
await trackEvent(
|
231
|
-
eventName: 'user_journey_step',
|
232
|
-
parameters: journeyData,
|
233
|
-
);
|
234
|
-
|
235
|
-
// Update journey state for funnel analysis
|
236
|
-
await _updateJourneyState(journeyName, stepName, stepData);
|
237
|
-
|
238
|
-
} catch (e) {
|
239
|
-
AnalyticsLogger.error('Journey tracking failed: $e');
|
240
|
-
}
|
241
|
-
}
|
242
|
-
|
243
|
-
// Performance event tracking
|
244
|
-
Future<void> trackPerformanceEvent({
|
245
|
-
required String performanceType,
|
246
|
-
required double value,
|
247
|
-
String? unit,
|
248
|
-
Map<String, dynamic>? metadata,
|
249
|
-
}) async {
|
250
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
251
|
-
|
252
|
-
try {
|
253
|
-
final performanceData = {
|
254
|
-
'performance_type': performanceType,
|
255
|
-
'value': value,
|
256
|
-
'unit': unit ?? 'ms',
|
257
|
-
'device_info': await _getDeviceInfo(),
|
258
|
-
'app_version': await _getAppVersion(),
|
259
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
260
|
-
...?metadata,
|
261
|
-
};
|
262
|
-
|
263
|
-
await trackEvent(
|
264
|
-
eventName: 'performance_metric',
|
265
|
-
parameters: performanceData,
|
266
|
-
);
|
267
|
-
|
268
|
-
} catch (e) {
|
269
|
-
AnalyticsLogger.error('Performance tracking failed: $e');
|
270
|
-
}
|
271
|
-
}
|
272
|
-
|
273
|
-
// Error and crash tracking
|
274
|
-
Future<void> trackError({
|
275
|
-
required String errorType,
|
276
|
-
required String errorMessage,
|
277
|
-
String? stackTrace,
|
278
|
-
Map<String, dynamic>? errorContext,
|
279
|
-
}) async {
|
280
|
-
if (!_isInitialized) return; // Track errors even without consent for debugging
|
281
|
-
|
282
|
-
try {
|
283
|
-
final errorData = {
|
284
|
-
'error_type': errorType,
|
285
|
-
'error_message': errorMessage,
|
286
|
-
'stack_trace': stackTrace,
|
287
|
-
'error_context': errorContext ?? {},
|
288
|
-
'app_version': await _getAppVersion(),
|
289
|
-
'platform': Platform.isIOS ? 'ios' : 'android',
|
290
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
291
|
-
};
|
292
|
-
|
293
|
-
// Firebase Crashlytics
|
294
|
-
await FirebaseCrashlytics.instance.recordError(
|
295
|
-
errorMessage,
|
296
|
-
stackTrace != null ? StackTrace.fromString(stackTrace) : StackTrace.current,
|
297
|
-
context: errorData,
|
298
|
-
);
|
299
|
-
|
300
|
-
// Custom error tracking (if consent given)
|
301
|
-
if (_hasUserConsent) {
|
302
|
-
await trackEvent(
|
303
|
-
eventName: 'app_error',
|
304
|
-
parameters: errorData,
|
305
|
-
);
|
306
|
-
}
|
307
|
-
|
308
|
-
} catch (e) {
|
309
|
-
AnalyticsLogger.error('Error tracking failed: $e');
|
310
|
-
}
|
311
|
-
}
|
312
|
-
|
313
|
-
// User property management
|
314
|
-
Future<void> setUserProperties(Map<String, dynamic> properties) async {
|
315
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
316
|
-
|
317
|
-
try {
|
318
|
-
// Firebase user properties
|
319
|
-
for (final entry in properties.entries) {
|
320
|
-
await _firebaseAnalytics.setUserProperty(
|
321
|
-
name: entry.key,
|
322
|
-
value: entry.value?.toString(),
|
323
|
-
);
|
324
|
-
}
|
325
|
-
|
326
|
-
// Mixpanel user profile
|
327
|
-
await _mixpanel.getPeople().set(properties);
|
328
|
-
|
329
|
-
// Amplitude user properties
|
330
|
-
await _amplitude.setUserProperties(properties);
|
331
|
-
|
332
|
-
AnalyticsLogger.debug('User properties set: ${properties.keys}');
|
333
|
-
} catch (e) {
|
334
|
-
AnalyticsLogger.error('User properties setting failed: $e');
|
335
|
-
}
|
336
|
-
}
|
337
|
-
|
338
|
-
// User identification
|
339
|
-
Future<void> identifyUser({
|
340
|
-
required String userId,
|
341
|
-
Map<String, dynamic>? userTraits,
|
342
|
-
}) async {
|
343
|
-
if (!_isInitialized || !_hasUserConsent) return;
|
344
|
-
|
345
|
-
try {
|
346
|
-
// Firebase user ID
|
347
|
-
await _firebaseAnalytics.setUserId(id: userId);
|
348
|
-
|
349
|
-
// Mixpanel identify
|
350
|
-
await _mixpanel.identify(userId);
|
351
|
-
if (userTraits != null) {
|
352
|
-
await _mixpanel.getPeople().set(userTraits);
|
353
|
-
}
|
354
|
-
|
355
|
-
// Amplitude identify
|
356
|
-
await _amplitude.setUserId(userId);
|
357
|
-
if (userTraits != null) {
|
358
|
-
await _amplitude.setUserProperties(userTraits);
|
359
|
-
}
|
360
|
-
|
361
|
-
AnalyticsLogger.info('User identified: $userId');
|
362
|
-
} catch (e) {
|
363
|
-
AnalyticsLogger.error('User identification failed: $e');
|
364
|
-
}
|
365
|
-
}
|
366
|
-
|
367
|
-
// Privacy compliance methods
|
368
|
-
Future<void> updateConsentStatus(bool hasConsent) async {
|
369
|
-
_hasUserConsent = hasConsent;
|
370
|
-
|
371
|
-
if (!hasConsent) {
|
372
|
-
await _clearUserData();
|
373
|
-
await _disableTracking();
|
374
|
-
} else {
|
375
|
-
await _enableTracking();
|
376
|
-
}
|
377
|
-
|
378
|
-
AnalyticsLogger.info('Consent status updated: $hasConsent');
|
379
|
-
}
|
380
|
-
|
381
|
-
Future<void> _clearUserData() async {
|
382
|
-
try {
|
383
|
-
await _firebaseAnalytics.resetAnalyticsData();
|
384
|
-
await _mixpanel.reset();
|
385
|
-
await _amplitude.regenerateDeviceId();
|
386
|
-
} catch (e) {
|
387
|
-
AnalyticsLogger.error('User data clearing failed: $e');
|
388
|
-
}
|
389
|
-
}
|
390
|
-
|
391
|
-
// Helper methods
|
392
|
-
Map<String, dynamic> _enrichEventParameters(
|
393
|
-
Map<String, dynamic>? parameters,
|
394
|
-
AnalyticsContext? context,
|
395
|
-
) {
|
396
|
-
final enriched = <String, dynamic>{
|
397
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
398
|
-
'platform': Platform.isIOS ? 'ios' : 'android',
|
399
|
-
...?parameters,
|
400
|
-
};
|
401
|
-
|
402
|
-
if (context != null) {
|
403
|
-
enriched.addAll(context.toMap());
|
404
|
-
}
|
405
|
-
|
406
|
-
return enriched;
|
407
|
-
}
|
408
|
-
|
409
|
-
String _sanitizeEventName(String eventName) {
|
410
|
-
return eventName.toLowerCase().replaceAll(RegExp(r'[^a-z0-9_]'), '_');
|
411
|
-
}
|
412
|
-
|
413
|
-
Future<Map<String, dynamic>> _getDeviceInfo() async {
|
414
|
-
final deviceInfo = DeviceInfoPlugin();
|
415
|
-
|
416
|
-
if (Platform.isAndroid) {
|
417
|
-
final androidInfo = await deviceInfo.androidInfo;
|
418
|
-
return {
|
419
|
-
'device_model': androidInfo.model,
|
420
|
-
'device_brand': androidInfo.brand,
|
421
|
-
'os_version': androidInfo.version.release,
|
422
|
-
'sdk_version': androidInfo.version.sdkInt,
|
423
|
-
};
|
424
|
-
} else if (Platform.isIOS) {
|
425
|
-
final iosInfo = await deviceInfo.iosInfo;
|
426
|
-
return {
|
427
|
-
'device_model': iosInfo.model,
|
428
|
-
'device_name': iosInfo.name,
|
429
|
-
'os_version': iosInfo.systemVersion,
|
430
|
-
'is_simulator': !iosInfo.isPhysicalDevice,
|
431
|
-
};
|
432
|
-
}
|
433
|
-
|
434
|
-
return {};
|
435
|
-
}
|
436
|
-
|
437
|
-
Future<String> _getAppVersion() async {
|
438
|
-
final packageInfo = await PackageInfo.fromPlatform();
|
439
|
-
return '${packageInfo.version}+${packageInfo.buildNumber}';
|
440
|
-
}
|
441
|
-
}
|
442
|
-
|
443
|
-
// Analytics Context for enriched event data
|
444
|
-
class AnalyticsContext {
|
445
|
-
final String? userId;
|
446
|
-
final String? sessionId;
|
447
|
-
final String? currentScreen;
|
448
|
-
final Map<String, dynamic>? customData;
|
449
|
-
|
450
|
-
AnalyticsContext({
|
451
|
-
this.userId,
|
452
|
-
this.sessionId,
|
453
|
-
this.currentScreen,
|
454
|
-
this.customData,
|
455
|
-
});
|
456
|
-
|
457
|
-
Map<String, dynamic> toMap() {
|
458
|
-
return {
|
459
|
-
if (userId != null) 'user_id': userId,
|
460
|
-
if (sessionId != null) 'session_id': sessionId,
|
461
|
-
if (currentScreen != null) 'current_screen': currentScreen,
|
462
|
-
if (customData != null) ...customData!,
|
463
|
-
};
|
464
|
-
}
|
465
|
-
}
|
466
|
-
```
|
467
|
-
|
468
|
-
### React Native Analytics Implementation
|
469
|
-
|
470
|
-
**React Native Analytics Service:**
|
471
|
-
```typescript
|
472
|
-
// Comprehensive Analytics Service for React Native
|
473
|
-
class ReactNativeAnalyticsService {
|
474
|
-
private static instance: ReactNativeAnalyticsService;
|
475
|
-
private initialized = false;
|
476
|
-
private hasUserConsent = false;
|
477
|
-
|
478
|
-
private analytics?: Analytics;
|
479
|
-
private amplitude?: AmplitudeReactNative;
|
480
|
-
private mixpanel?: MixpanelReactNative;
|
481
|
-
|
482
|
-
static getInstance(): ReactNativeAnalyticsService {
|
483
|
-
if (!ReactNativeAnalyticsService.instance) {
|
484
|
-
ReactNativeAnalyticsService.instance = new ReactNativeAnalyticsService();
|
485
|
-
}
|
486
|
-
return ReactNativeAnalyticsService.instance;
|
487
|
-
}
|
488
|
-
|
489
|
-
async initialize(config: AnalyticsConfig): Promise<void> {
|
490
|
-
this.hasUserConsent = config.hasUserConsent;
|
491
|
-
|
492
|
-
if (!this.hasUserConsent) {
|
493
|
-
console.log('Analytics initialized without user consent - limited tracking');
|
494
|
-
return;
|
495
|
-
}
|
496
|
-
|
497
|
-
try {
|
498
|
-
// Initialize Firebase Analytics
|
499
|
-
this.analytics = analytics();
|
500
|
-
await this.analytics.setAnalyticsCollectionEnabled(true);
|
501
|
-
|
502
|
-
// Initialize Amplitude
|
503
|
-
this.amplitude = new AmplitudeReactNative(config.amplitudeKey);
|
504
|
-
await this.amplitude.init();
|
505
|
-
|
506
|
-
// Initialize Mixpanel
|
507
|
-
this.mixpanel = new MixpanelReactNative(config.mixpanelToken);
|
508
|
-
|
509
|
-
// Set initial user properties
|
510
|
-
if (config.userProperties) {
|
511
|
-
await this.setUserProperties(config.userProperties);
|
512
|
-
}
|
513
|
-
|
514
|
-
this.initialized = true;
|
515
|
-
console.log('Analytics services initialized successfully');
|
516
|
-
} catch (error) {
|
517
|
-
console.error('Analytics initialization failed:', error);
|
518
|
-
}
|
519
|
-
}
|
520
|
-
|
521
|
-
async trackEvent(
|
522
|
-
eventName: string,
|
523
|
-
parameters?: Record<string, any>,
|
524
|
-
context?: AnalyticsContext,
|
525
|
-
): Promise<void> {
|
526
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
527
|
-
|
528
|
-
try {
|
529
|
-
const enrichedParameters = this.enrichEventParameters(parameters, context);
|
530
|
-
|
531
|
-
// Firebase Analytics
|
532
|
-
await this.analytics?.logEvent(this.sanitizeEventName(eventName), enrichedParameters);
|
533
|
-
|
534
|
-
// Amplitude
|
535
|
-
await this.amplitude?.logEvent(eventName, enrichedParameters);
|
536
|
-
|
537
|
-
// Mixpanel
|
538
|
-
await this.mixpanel?.track(eventName, enrichedParameters);
|
539
|
-
|
540
|
-
console.log(`Event tracked: ${eventName}`);
|
541
|
-
} catch (error) {
|
542
|
-
console.error('Event tracking failed:', error);
|
543
|
-
}
|
544
|
-
}
|
545
|
-
|
546
|
-
async trackScreenView(
|
547
|
-
screenName: string,
|
548
|
-
screenClass?: string,
|
549
|
-
parameters?: Record<string, any>,
|
550
|
-
): Promise<void> {
|
551
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
552
|
-
|
553
|
-
try {
|
554
|
-
const screenParameters = {
|
555
|
-
screen_name: screenName,
|
556
|
-
screen_class: screenClass || screenName,
|
557
|
-
timestamp: Date.now(),
|
558
|
-
...parameters,
|
559
|
-
};
|
560
|
-
|
561
|
-
// Firebase screen tracking
|
562
|
-
await this.analytics?.logScreenView({
|
563
|
-
screen_name: screenName,
|
564
|
-
screen_class: screenClass,
|
565
|
-
...screenParameters,
|
566
|
-
});
|
567
|
-
|
568
|
-
// Amplitude screen tracking
|
569
|
-
await this.amplitude?.logEvent('Screen View', screenParameters);
|
570
|
-
|
571
|
-
// Mixpanel screen tracking
|
572
|
-
await this.mixpanel?.track('Screen View', screenParameters);
|
573
|
-
|
574
|
-
console.log(`Screen view tracked: ${screenName}`);
|
575
|
-
} catch (error) {
|
576
|
-
console.error('Screen tracking failed:', error);
|
577
|
-
}
|
578
|
-
}
|
579
|
-
|
580
|
-
async trackUserJourney(
|
581
|
-
journeyName: string,
|
582
|
-
stepName: string,
|
583
|
-
stepData?: Record<string, any>,
|
584
|
-
): Promise<void> {
|
585
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
586
|
-
|
587
|
-
try {
|
588
|
-
const journeyData = {
|
589
|
-
journey_name: journeyName,
|
590
|
-
step_name: stepName,
|
591
|
-
step_timestamp: Date.now(),
|
592
|
-
step_data: stepData || {},
|
593
|
-
};
|
594
|
-
|
595
|
-
await this.trackEvent('user_journey_step', journeyData);
|
596
|
-
|
597
|
-
// Update journey state for funnel analysis
|
598
|
-
await this.updateJourneyState(journeyName, stepName, stepData);
|
599
|
-
} catch (error) {
|
600
|
-
console.error('Journey tracking failed:', error);
|
601
|
-
}
|
602
|
-
}
|
603
|
-
|
604
|
-
async trackPerformanceMetric(
|
605
|
-
metricName: string,
|
606
|
-
value: number,
|
607
|
-
unit?: string,
|
608
|
-
metadata?: Record<string, any>,
|
609
|
-
): Promise<void> {
|
610
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
611
|
-
|
612
|
-
try {
|
613
|
-
const performanceData = {
|
614
|
-
performance_type: metricName,
|
615
|
-
value,
|
616
|
-
unit: unit || 'ms',
|
617
|
-
device_info: await this.getDeviceInfo(),
|
618
|
-
app_version: await this.getAppVersion(),
|
619
|
-
timestamp: Date.now(),
|
620
|
-
...metadata,
|
621
|
-
};
|
622
|
-
|
623
|
-
await this.trackEvent('performance_metric', performanceData);
|
624
|
-
} catch (error) {
|
625
|
-
console.error('Performance tracking failed:', error);
|
626
|
-
}
|
627
|
-
}
|
628
|
-
|
629
|
-
async trackError(
|
630
|
-
errorType: string,
|
631
|
-
errorMessage: string,
|
632
|
-
stackTrace?: string,
|
633
|
-
errorContext?: Record<string, any>,
|
634
|
-
): Promise<void> {
|
635
|
-
if (!this.initialized) return; // Track errors even without consent
|
636
|
-
|
637
|
-
try {
|
638
|
-
const errorData = {
|
639
|
-
error_type: errorType,
|
640
|
-
error_message: errorMessage,
|
641
|
-
stack_trace: stackTrace,
|
642
|
-
error_context: errorContext || {},
|
643
|
-
app_version: await this.getAppVersion(),
|
644
|
-
platform: Platform.OS,
|
645
|
-
timestamp: Date.now(),
|
646
|
-
};
|
647
|
-
|
648
|
-
// Crashlytics
|
649
|
-
crashlytics().recordError(new Error(errorMessage), errorData);
|
650
|
-
|
651
|
-
// Custom error tracking (if consent given)
|
652
|
-
if (this.hasUserConsent) {
|
653
|
-
await this.trackEvent('app_error', errorData);
|
654
|
-
}
|
655
|
-
} catch (error) {
|
656
|
-
console.error('Error tracking failed:', error);
|
657
|
-
}
|
658
|
-
}
|
659
|
-
|
660
|
-
async setUserProperties(properties: Record<string, any>): Promise<void> {
|
661
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
662
|
-
|
663
|
-
try {
|
664
|
-
// Firebase user properties
|
665
|
-
for (const [key, value] of Object.entries(properties)) {
|
666
|
-
await this.analytics?.setUserProperty(key, String(value));
|
667
|
-
}
|
668
|
-
|
669
|
-
// Amplitude user properties
|
670
|
-
await this.amplitude?.setUserProperties(properties);
|
671
|
-
|
672
|
-
// Mixpanel user profile
|
673
|
-
await this.mixpanel?.getPeople().set(properties);
|
674
|
-
|
675
|
-
console.log('User properties set:', Object.keys(properties));
|
676
|
-
} catch (error) {
|
677
|
-
console.error('User properties setting failed:', error);
|
678
|
-
}
|
679
|
-
}
|
680
|
-
|
681
|
-
async identifyUser(
|
682
|
-
userId: string,
|
683
|
-
userTraits?: Record<string, any>,
|
684
|
-
): Promise<void> {
|
685
|
-
if (!this.initialized || !this.hasUserConsent) return;
|
686
|
-
|
687
|
-
try {
|
688
|
-
// Firebase user ID
|
689
|
-
await this.analytics?.setUserId(userId);
|
690
|
-
|
691
|
-
// Amplitude identify
|
692
|
-
await this.amplitude?.setUserId(userId);
|
693
|
-
if (userTraits) {
|
694
|
-
await this.amplitude?.setUserProperties(userTraits);
|
695
|
-
}
|
696
|
-
|
697
|
-
// Mixpanel identify
|
698
|
-
await this.mixpanel?.identify(userId);
|
699
|
-
if (userTraits) {
|
700
|
-
await this.mixpanel?.getPeople().set(userTraits);
|
701
|
-
}
|
702
|
-
|
703
|
-
console.log('User identified:', userId);
|
704
|
-
} catch (error) {
|
705
|
-
console.error('User identification failed:', error);
|
706
|
-
}
|
707
|
-
}
|
708
|
-
|
709
|
-
// Privacy compliance methods
|
710
|
-
async updateConsentStatus(hasConsent: boolean): Promise<void> {
|
711
|
-
this.hasUserConsent = hasConsent;
|
712
|
-
|
713
|
-
if (!hasConsent) {
|
714
|
-
await this.clearUserData();
|
715
|
-
await this.disableTracking();
|
716
|
-
} else {
|
717
|
-
await this.enableTracking();
|
718
|
-
}
|
719
|
-
|
720
|
-
console.log('Consent status updated:', hasConsent);
|
721
|
-
}
|
722
|
-
|
723
|
-
private async clearUserData(): Promise<void> {
|
724
|
-
try {
|
725
|
-
await this.analytics?.resetAnalyticsData();
|
726
|
-
await this.amplitude?.reset();
|
727
|
-
await this.mixpanel?.reset();
|
728
|
-
} catch (error) {
|
729
|
-
console.error('User data clearing failed:', error);
|
730
|
-
}
|
731
|
-
}
|
732
|
-
|
733
|
-
private enrichEventParameters(
|
734
|
-
parameters?: Record<string, any>,
|
735
|
-
context?: AnalyticsContext,
|
736
|
-
): Record<string, any> {
|
737
|
-
const enriched = {
|
738
|
-
timestamp: Date.now(),
|
739
|
-
platform: Platform.OS,
|
740
|
-
...parameters,
|
741
|
-
};
|
742
|
-
|
743
|
-
if (context) {
|
744
|
-
Object.assign(enriched, context.toObject());
|
745
|
-
}
|
746
|
-
|
747
|
-
return enriched;
|
748
|
-
}
|
749
|
-
|
750
|
-
private sanitizeEventName(eventName: string): string {
|
751
|
-
return eventName.toLowerCase().replace(/[^a-z0-9_]/g, '_');
|
752
|
-
}
|
753
|
-
|
754
|
-
private async getDeviceInfo(): Promise<Record<string, any>> {
|
755
|
-
const deviceInfo = {
|
756
|
-
device_model: DeviceInfo.getModel(),
|
757
|
-
device_brand: DeviceInfo.getBrand(),
|
758
|
-
os_version: DeviceInfo.getSystemVersion(),
|
759
|
-
app_version: DeviceInfo.getVersion(),
|
760
|
-
};
|
761
|
-
|
762
|
-
return deviceInfo;
|
763
|
-
}
|
764
|
-
|
765
|
-
private async getAppVersion(): Promise<string> {
|
766
|
-
const version = DeviceInfo.getVersion();
|
767
|
-
const buildNumber = DeviceInfo.getBuildNumber();
|
768
|
-
return `${version}+${buildNumber}`;
|
769
|
-
}
|
770
|
-
}
|
771
|
-
|
772
|
-
// Analytics Context for React Native
|
773
|
-
class AnalyticsContext {
|
774
|
-
constructor(
|
775
|
-
public userId?: string,
|
776
|
-
public sessionId?: string,
|
777
|
-
public currentScreen?: string,
|
778
|
-
public customData?: Record<string, any>,
|
779
|
-
) {}
|
780
|
-
|
781
|
-
toObject(): Record<string, any> {
|
782
|
-
return {
|
783
|
-
...(this.userId && { user_id: this.userId }),
|
784
|
-
...(this.sessionId && { session_id: this.sessionId }),
|
785
|
-
...(this.currentScreen && { current_screen: this.currentScreen }),
|
786
|
-
...this.customData,
|
787
|
-
};
|
788
|
-
}
|
789
|
-
}
|
790
|
-
```
|
791
|
-
|
792
|
-
## Performance Analytics Implementation
|
793
|
-
|
794
|
-
### App Performance Monitoring
|
795
|
-
|
796
|
-
**Performance Metrics Collection:**
|
797
|
-
```dart
|
798
|
-
// Flutter Performance Monitoring
|
799
|
-
class PerformanceMonitoringService {
|
800
|
-
static final PerformanceMonitoringService _instance = PerformanceMonitoringService._internal();
|
801
|
-
factory PerformanceMonitoringService() => _instance;
|
802
|
-
PerformanceMonitoringService._internal();
|
803
|
-
|
804
|
-
final FlutterAnalyticsService _analytics = FlutterAnalyticsService();
|
805
|
-
Timer? _performanceTimer;
|
806
|
-
|
807
|
-
void startPerformanceMonitoring() {
|
808
|
-
// Monitor app launch time
|
809
|
-
_monitorAppLaunchTime();
|
810
|
-
|
811
|
-
// Monitor frame rendering performance
|
812
|
-
_monitorFramePerformance();
|
813
|
-
|
814
|
-
// Monitor memory usage
|
815
|
-
_startMemoryMonitoring();
|
816
|
-
|
817
|
-
// Monitor network performance
|
818
|
-
_setupNetworkPerformanceTracking();
|
819
|
-
}
|
820
|
-
|
821
|
-
void _monitorAppLaunchTime() {
|
822
|
-
WidgetsBinding.instance.addPostFrameCallback((_) {
|
823
|
-
final appLaunchTime = DateTime.now().millisecondsSinceEpoch - _appStartTime;
|
824
|
-
|
825
|
-
_analytics.trackPerformanceEvent(
|
826
|
-
performanceType: 'app_launch_time',
|
827
|
-
value: appLaunchTime.toDouble(),
|
828
|
-
unit: 'ms',
|
829
|
-
metadata: {
|
830
|
-
'launch_type': 'cold_start',
|
831
|
-
'device_tier': _getDeviceTier(),
|
832
|
-
},
|
833
|
-
);
|
834
|
-
});
|
835
|
-
}
|
836
|
-
|
837
|
-
void _monitorFramePerformance() {
|
838
|
-
WidgetsBinding.instance.addTimingsCallback(_onFrameCallback);
|
839
|
-
}
|
840
|
-
|
841
|
-
void _onFrameCallback(List<FrameTiming> timings) {
|
842
|
-
for (final timing in timings) {
|
843
|
-
final frameDuration = timing.totalSpan.inMicroseconds / 1000.0;
|
844
|
-
|
845
|
-
if (frameDuration > 16.67) { // Frame took longer than 60fps
|
846
|
-
_analytics.trackPerformanceEvent(
|
847
|
-
performanceType: 'frame_drop',
|
848
|
-
value: frameDuration,
|
849
|
-
unit: 'ms',
|
850
|
-
metadata: {
|
851
|
-
'frame_number': timing.frameNumber,
|
852
|
-
'build_duration': timing.buildDuration.inMicroseconds / 1000.0,
|
853
|
-
'raster_duration': timing.rasterDuration.inMicroseconds / 1000.0,
|
854
|
-
},
|
855
|
-
);
|
856
|
-
}
|
857
|
-
}
|
858
|
-
}
|
859
|
-
|
860
|
-
void _startMemoryMonitoring() {
|
861
|
-
_performanceTimer = Timer.periodic(Duration(minutes: 1), (timer) async {
|
862
|
-
final memoryUsage = await _getMemoryUsage();
|
863
|
-
|
864
|
-
_analytics.trackPerformanceEvent(
|
865
|
-
performanceType: 'memory_usage',
|
866
|
-
value: memoryUsage,
|
867
|
-
unit: 'MB',
|
868
|
-
metadata: {
|
869
|
-
'measurement_type': 'periodic',
|
870
|
-
},
|
871
|
-
);
|
872
|
-
|
873
|
-
// Alert on high memory usage
|
874
|
-
if (memoryUsage > 150) {
|
875
|
-
_analytics.trackEvent(
|
876
|
-
eventName: 'high_memory_usage_detected',
|
877
|
-
parameters: {
|
878
|
-
'memory_usage_mb': memoryUsage,
|
879
|
-
'threshold_mb': 150,
|
880
|
-
},
|
881
|
-
);
|
882
|
-
}
|
883
|
-
});
|
884
|
-
}
|
885
|
-
|
886
|
-
void _setupNetworkPerformanceTracking() {
|
887
|
-
// Intercept HTTP requests to measure network performance
|
888
|
-
HttpOverrides.global = NetworkPerformanceHttpOverrides(_analytics);
|
889
|
-
}
|
890
|
-
|
891
|
-
// Screen transition performance
|
892
|
-
void trackScreenTransition({
|
893
|
-
required String fromScreen,
|
894
|
-
required String toScreen,
|
895
|
-
required int transitionDuration,
|
896
|
-
}) {
|
897
|
-
_analytics.trackPerformanceEvent(
|
898
|
-
performanceType: 'screen_transition',
|
899
|
-
value: transitionDuration.toDouble(),
|
900
|
-
unit: 'ms',
|
901
|
-
metadata: {
|
902
|
-
'from_screen': fromScreen,
|
903
|
-
'to_screen': toScreen,
|
904
|
-
'transition_type': 'navigation',
|
905
|
-
},
|
906
|
-
);
|
907
|
-
}
|
908
|
-
|
909
|
-
// Feature performance tracking
|
910
|
-
Future<T> trackFeaturePerformance<T>({
|
911
|
-
required String featureName,
|
912
|
-
required Future<T> Function() operation,
|
913
|
-
Map<String, dynamic>? metadata,
|
914
|
-
}) async {
|
915
|
-
final stopwatch = Stopwatch()..start();
|
916
|
-
|
917
|
-
try {
|
918
|
-
final result = await operation();
|
919
|
-
stopwatch.stop();
|
920
|
-
|
921
|
-
_analytics.trackPerformanceEvent(
|
922
|
-
performanceType: 'feature_performance',
|
923
|
-
value: stopwatch.elapsedMilliseconds.toDouble(),
|
924
|
-
unit: 'ms',
|
925
|
-
metadata: {
|
926
|
-
'feature_name': featureName,
|
927
|
-
'operation_status': 'success',
|
928
|
-
...?metadata,
|
929
|
-
},
|
930
|
-
);
|
931
|
-
|
932
|
-
return result;
|
933
|
-
} catch (e) {
|
934
|
-
stopwatch.stop();
|
935
|
-
|
936
|
-
_analytics.trackPerformanceEvent(
|
937
|
-
performanceType: 'feature_performance',
|
938
|
-
value: stopwatch.elapsedMilliseconds.toDouble(),
|
939
|
-
unit: 'ms',
|
940
|
-
metadata: {
|
941
|
-
'feature_name': featureName,
|
942
|
-
'operation_status': 'error',
|
943
|
-
'error_message': e.toString(),
|
944
|
-
...?metadata,
|
945
|
-
},
|
946
|
-
);
|
947
|
-
|
948
|
-
rethrow;
|
949
|
-
}
|
950
|
-
}
|
951
|
-
|
952
|
-
Future<double> _getMemoryUsage() async {
|
953
|
-
// Platform-specific memory usage calculation
|
954
|
-
if (Platform.isAndroid) {
|
955
|
-
return await _getAndroidMemoryUsage();
|
956
|
-
} else if (Platform.isIOS) {
|
957
|
-
return await _getIOSMemoryUsage();
|
958
|
-
}
|
959
|
-
return 0.0;
|
960
|
-
}
|
961
|
-
|
962
|
-
String _getDeviceTier() {
|
963
|
-
// Classify device performance tier based on hardware specs
|
964
|
-
// This would be implemented based on device capabilities
|
965
|
-
return 'mid_tier'; // Placeholder
|
966
|
-
}
|
967
|
-
}
|
968
|
-
|
969
|
-
// Network Performance HTTP Override
|
970
|
-
class NetworkPerformanceHttpOverrides extends HttpOverrides {
|
971
|
-
final FlutterAnalyticsService analytics;
|
972
|
-
|
973
|
-
NetworkPerformanceHttpOverrides(this.analytics);
|
974
|
-
|
975
|
-
@override
|
976
|
-
HttpClient createHttpClient(SecurityContext? context) {
|
977
|
-
final client = super.createHttpClient(context);
|
978
|
-
|
979
|
-
// Add network performance tracking
|
980
|
-
client.connectionTimeout = Duration(seconds: 10);
|
981
|
-
client.idleTimeout = Duration(seconds: 30);
|
982
|
-
|
983
|
-
return PerformanceTrackingHttpClient(client, analytics);
|
984
|
-
}
|
985
|
-
}
|
986
|
-
|
987
|
-
class PerformanceTrackingHttpClient implements HttpClient {
|
988
|
-
final HttpClient _inner;
|
989
|
-
final FlutterAnalyticsService _analytics;
|
990
|
-
|
991
|
-
PerformanceTrackingHttpClient(this._inner, this._analytics);
|
992
|
-
|
993
|
-
@override
|
994
|
-
Future<HttpClientRequest> openUrl(String method, Uri url) async {
|
995
|
-
final stopwatch = Stopwatch()..start();
|
996
|
-
|
997
|
-
try {
|
998
|
-
final request = await _inner.openUrl(method, url);
|
999
|
-
return PerformanceTrackingHttpClientRequest(request, _analytics, stopwatch, url);
|
1000
|
-
} catch (e) {
|
1001
|
-
stopwatch.stop();
|
1002
|
-
|
1003
|
-
_analytics.trackPerformanceEvent(
|
1004
|
-
performanceType: 'network_request',
|
1005
|
-
value: stopwatch.elapsedMilliseconds.toDouble(),
|
1006
|
-
unit: 'ms',
|
1007
|
-
metadata: {
|
1008
|
-
'method': method,
|
1009
|
-
'url': url.toString(),
|
1010
|
-
'status': 'connection_failed',
|
1011
|
-
'error': e.toString(),
|
1012
|
-
},
|
1013
|
-
);
|
1014
|
-
|
1015
|
-
rethrow;
|
1016
|
-
}
|
1017
|
-
}
|
1018
|
-
|
1019
|
-
// Implement other HttpClient methods...
|
1020
|
-
}
|
1021
|
-
```
|
1022
|
-
|
1023
|
-
## User Behavior Analytics
|
1024
|
-
|
1025
|
-
### User Journey and Funnel Analysis
|
1026
|
-
|
1027
|
-
**User Behavior Tracking Implementation:**
|
1028
|
-
```dart
|
1029
|
-
// User Behavior Analytics Service
|
1030
|
-
class UserBehaviorAnalyticsService {
|
1031
|
-
final FlutterAnalyticsService _analytics = FlutterAnalyticsService();
|
1032
|
-
final Map<String, UserSession> _activeSessions = {};
|
1033
|
-
final Map<String, List<UserAction>> _sessionActions = {};
|
1034
|
-
|
1035
|
-
// Start user session tracking
|
1036
|
-
void startSession(String userId) {
|
1037
|
-
final sessionId = _generateSessionId();
|
1038
|
-
final session = UserSession(
|
1039
|
-
id: sessionId,
|
1040
|
-
userId: userId,
|
1041
|
-
startTime: DateTime.now(),
|
1042
|
-
deviceInfo: _getDeviceInfo(),
|
1043
|
-
);
|
1044
|
-
|
1045
|
-
_activeSessions[userId] = session;
|
1046
|
-
_sessionActions[sessionId] = [];
|
1047
|
-
|
1048
|
-
_analytics.trackEvent(
|
1049
|
-
eventName: 'session_start',
|
1050
|
-
parameters: session.toAnalyticsData(),
|
1051
|
-
);
|
1052
|
-
}
|
1053
|
-
|
1054
|
-
// Track user actions within session
|
1055
|
-
void trackUserAction({
|
1056
|
-
required String userId,
|
1057
|
-
required String actionType,
|
1058
|
-
required String actionTarget,
|
1059
|
-
Map<String, dynamic>? actionData,
|
1060
|
-
}) {
|
1061
|
-
final session = _activeSessions[userId];
|
1062
|
-
if (session == null) return;
|
1063
|
-
|
1064
|
-
final action = UserAction(
|
1065
|
-
type: actionType,
|
1066
|
-
target: actionTarget,
|
1067
|
-
timestamp: DateTime.now(),
|
1068
|
-
data: actionData ?? {},
|
1069
|
-
);
|
1070
|
-
|
1071
|
-
_sessionActions[session.id]?.add(action);
|
1072
|
-
|
1073
|
-
_analytics.trackEvent(
|
1074
|
-
eventName: 'user_action',
|
1075
|
-
parameters: {
|
1076
|
-
'session_id': session.id,
|
1077
|
-
'action_type': actionType,
|
1078
|
-
'action_target': actionTarget,
|
1079
|
-
'action_data': actionData ?? {},
|
1080
|
-
'session_duration': DateTime.now().difference(session.startTime).inMilliseconds,
|
1081
|
-
},
|
1082
|
-
);
|
1083
|
-
}
|
1084
|
-
|
1085
|
-
// Track feature usage and adoption
|
1086
|
-
void trackFeatureUsage({
|
1087
|
-
required String userId,
|
1088
|
-
required String featureName,
|
1089
|
-
required String usageType, // 'first_use', 'regular_use', 'advanced_use'
|
1090
|
-
Map<String, dynamic>? featureData,
|
1091
|
-
}) {
|
1092
|
-
_analytics.trackEvent(
|
1093
|
-
eventName: 'feature_usage',
|
1094
|
-
parameters: {
|
1095
|
-
'feature_name': featureName,
|
1096
|
-
'usage_type': usageType,
|
1097
|
-
'feature_data': featureData ?? {},
|
1098
|
-
'user_id': userId,
|
1099
|
-
},
|
1100
|
-
);
|
1101
|
-
|
1102
|
-
// Track feature adoption funnel
|
1103
|
-
_trackFeatureAdoptionStep(userId, featureName, usageType);
|
1104
|
-
}
|
1105
|
-
|
1106
|
-
// Track conversion funnels
|
1107
|
-
void trackConversionFunnel({
|
1108
|
-
required String userId,
|
1109
|
-
required String funnelName,
|
1110
|
-
required String stepName,
|
1111
|
-
Map<String, dynamic>? stepData,
|
1112
|
-
}) {
|
1113
|
-
_analytics.trackUserJourney(
|
1114
|
-
journeyName: funnelName,
|
1115
|
-
stepName: stepName,
|
1116
|
-
stepData: {
|
1117
|
-
'user_id': userId,
|
1118
|
-
'step_data': stepData ?? {},
|
1119
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
1120
|
-
},
|
1121
|
-
);
|
1122
|
-
|
1123
|
-
// Update funnel state in local storage for offline analysis
|
1124
|
-
_updateFunnelProgress(userId, funnelName, stepName);
|
1125
|
-
}
|
1126
|
-
|
1127
|
-
// Track user engagement metrics
|
1128
|
-
void trackEngagementMetric({
|
1129
|
-
required String userId,
|
1130
|
-
required String metricType,
|
1131
|
-
required double value,
|
1132
|
-
String? unit,
|
1133
|
-
Map<String, dynamic>? context,
|
1134
|
-
}) {
|
1135
|
-
_analytics.trackEvent(
|
1136
|
-
eventName: 'engagement_metric',
|
1137
|
-
parameters: {
|
1138
|
-
'metric_type': metricType,
|
1139
|
-
'value': value,
|
1140
|
-
'unit': unit ?? 'count',
|
1141
|
-
'user_id': userId,
|
1142
|
-
'context': context ?? {},
|
1143
|
-
},
|
1144
|
-
);
|
1145
|
-
}
|
1146
|
-
|
1147
|
-
// End user session and analyze behavior
|
1148
|
-
void endSession(String userId) {
|
1149
|
-
final session = _activeSessions[userId];
|
1150
|
-
if (session == null) return;
|
1151
|
-
|
1152
|
-
final sessionDuration = DateTime.now().difference(session.startTime);
|
1153
|
-
final sessionActions = _sessionActions[session.id] ?? [];
|
1154
|
-
|
1155
|
-
// Analyze session behavior
|
1156
|
-
final behaviorAnalysis = _analyzeSessionBehavior(session, sessionActions);
|
1157
|
-
|
1158
|
-
_analytics.trackEvent(
|
1159
|
-
eventName: 'session_end',
|
1160
|
-
parameters: {
|
1161
|
-
'session_id': session.id,
|
1162
|
-
'session_duration_ms': sessionDuration.inMilliseconds,
|
1163
|
-
'action_count': sessionActions.length,
|
1164
|
-
'behavior_analysis': behaviorAnalysis,
|
1165
|
-
},
|
1166
|
-
);
|
1167
|
-
|
1168
|
-
// Clean up session data
|
1169
|
-
_activeSessions.remove(userId);
|
1170
|
-
_sessionActions.remove(session.id);
|
1171
|
-
}
|
1172
|
-
|
1173
|
-
// Analyze user behavior patterns
|
1174
|
-
Map<String, dynamic> _analyzeSessionBehavior(
|
1175
|
-
UserSession session,
|
1176
|
-
List<UserAction> actions,
|
1177
|
-
) {
|
1178
|
-
final actionTypes = actions.map((a) => a.type).toSet();
|
1179
|
-
final actionTargets = actions.map((a) => a.target).toSet();
|
1180
|
-
final screenTransitions = _calculateScreenTransitions(actions);
|
1181
|
-
|
1182
|
-
return {
|
1183
|
-
'unique_actions': actionTypes.length,
|
1184
|
-
'unique_targets': actionTargets.length,
|
1185
|
-
'screen_transitions': screenTransitions.length,
|
1186
|
-
'most_used_feature': _getMostUsedFeature(actions),
|
1187
|
-
'engagement_score': _calculateEngagementScore(session, actions),
|
1188
|
-
};
|
1189
|
-
}
|
1190
|
-
|
1191
|
-
// A/B Testing Integration
|
1192
|
-
void trackABTestExposure({
|
1193
|
-
required String userId,
|
1194
|
-
required String testName,
|
1195
|
-
required String variant,
|
1196
|
-
Map<String, dynamic>? testData,
|
1197
|
-
}) {
|
1198
|
-
_analytics.trackEvent(
|
1199
|
-
eventName: 'ab_test_exposure',
|
1200
|
-
parameters: {
|
1201
|
-
'test_name': testName,
|
1202
|
-
'variant': variant,
|
1203
|
-
'user_id': userId,
|
1204
|
-
'test_data': testData ?? {},
|
1205
|
-
},
|
1206
|
-
);
|
1207
|
-
}
|
1208
|
-
|
1209
|
-
void trackABTestConversion({
|
1210
|
-
required String userId,
|
1211
|
-
required String testName,
|
1212
|
-
required String variant,
|
1213
|
-
required String conversionEvent,
|
1214
|
-
Map<String, dynamic>? conversionData,
|
1215
|
-
}) {
|
1216
|
-
_analytics.trackEvent(
|
1217
|
-
eventName: 'ab_test_conversion',
|
1218
|
-
parameters: {
|
1219
|
-
'test_name': testName,
|
1220
|
-
'variant': variant,
|
1221
|
-
'conversion_event': conversionEvent,
|
1222
|
-
'user_id': userId,
|
1223
|
-
'conversion_data': conversionData ?? {},
|
1224
|
-
},
|
1225
|
-
);
|
1226
|
-
}
|
1227
|
-
}
|
1228
|
-
|
1229
|
-
// User Session Model
|
1230
|
-
class UserSession {
|
1231
|
-
final String id;
|
1232
|
-
final String userId;
|
1233
|
-
final DateTime startTime;
|
1234
|
-
final Map<String, dynamic> deviceInfo;
|
1235
|
-
|
1236
|
-
UserSession({
|
1237
|
-
required this.id,
|
1238
|
-
required this.userId,
|
1239
|
-
required this.startTime,
|
1240
|
-
required this.deviceInfo,
|
1241
|
-
});
|
1242
|
-
|
1243
|
-
Map<String, dynamic> toAnalyticsData() {
|
1244
|
-
return {
|
1245
|
-
'session_id': id,
|
1246
|
-
'user_id': userId,
|
1247
|
-
'start_time': startTime.millisecondsSinceEpoch,
|
1248
|
-
'device_info': deviceInfo,
|
1249
|
-
};
|
1250
|
-
}
|
1251
|
-
}
|
1252
|
-
|
1253
|
-
// User Action Model
|
1254
|
-
class UserAction {
|
1255
|
-
final String type;
|
1256
|
-
final String target;
|
1257
|
-
final DateTime timestamp;
|
1258
|
-
final Map<String, dynamic> data;
|
1259
|
-
|
1260
|
-
UserAction({
|
1261
|
-
required this.type,
|
1262
|
-
required this.target,
|
1263
|
-
required this.timestamp,
|
1264
|
-
required this.data,
|
1265
|
-
});
|
1266
|
-
}
|
1267
|
-
```
|
1268
|
-
|
1269
|
-
## Privacy-Compliant Analytics
|
1270
|
-
|
1271
|
-
### GDPR/CCPA Compliance Implementation
|
1272
|
-
|
1273
|
-
**Privacy-First Analytics Service:**
|
1274
|
-
```dart
|
1275
|
-
// Privacy-Compliant Analytics Service
|
1276
|
-
class PrivacyCompliantAnalyticsService {
|
1277
|
-
final FlutterAnalyticsService _analytics = FlutterAnalyticsService();
|
1278
|
-
bool _hasAnalyticsConsent = false;
|
1279
|
-
bool _hasPersonalizationConsent = false;
|
1280
|
-
final Set<String> _consentedDataTypes = {};
|
1281
|
-
|
1282
|
-
// Consent management
|
1283
|
-
Future<void> updateConsent({
|
1284
|
-
required bool analyticsConsent,
|
1285
|
-
required bool personalizationConsent,
|
1286
|
-
required Set<String> consentedDataTypes,
|
1287
|
-
}) async {
|
1288
|
-
_hasAnalyticsConsent = analyticsConsent;
|
1289
|
-
_hasPersonalizationConsent = personalizationConsent;
|
1290
|
-
_consentedDataTypes.clear();
|
1291
|
-
_consentedDataTypes.addAll(consentedDataTypes);
|
1292
|
-
|
1293
|
-
// Update analytics services
|
1294
|
-
await _analytics.updateConsentStatus(analyticsConsent);
|
1295
|
-
|
1296
|
-
// Log consent change for audit trail
|
1297
|
-
_analytics.trackEvent(
|
1298
|
-
eventName: 'consent_updated',
|
1299
|
-
parameters: {
|
1300
|
-
'analytics_consent': analyticsConsent,
|
1301
|
-
'personalization_consent': personalizationConsent,
|
1302
|
-
'consented_data_types': consentedDataTypes.toList(),
|
1303
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
1304
|
-
},
|
1305
|
-
);
|
1306
|
-
}
|
1307
|
-
|
1308
|
-
// Privacy-aware event tracking
|
1309
|
-
Future<void> trackPrivacyAwareEvent({
|
1310
|
-
required String eventName,
|
1311
|
-
Map<String, dynamic>? parameters,
|
1312
|
-
required Set<String> requiredDataTypes,
|
1313
|
-
}) async {
|
1314
|
-
// Check if user has consented to required data types
|
1315
|
-
if (!_hasConsentForDataTypes(requiredDataTypes)) {
|
1316
|
-
// Track anonymized version without personal data
|
1317
|
-
await _trackAnonymizedEvent(eventName, parameters);
|
1318
|
-
return;
|
1319
|
-
}
|
1320
|
-
|
1321
|
-
// Full tracking with user consent
|
1322
|
-
await _analytics.trackEvent(
|
1323
|
-
eventName: eventName,
|
1324
|
-
parameters: parameters,
|
1325
|
-
);
|
1326
|
-
}
|
1327
|
-
|
1328
|
-
// Data anonymization for unconsented tracking
|
1329
|
-
Future<void> _trackAnonymizedEvent(
|
1330
|
-
String eventName,
|
1331
|
-
Map<String, dynamic>? parameters,
|
1332
|
-
) async {
|
1333
|
-
if (!_hasAnalyticsConsent) return;
|
1334
|
-
|
1335
|
-
final anonymizedParameters = _anonymizeParameters(parameters);
|
1336
|
-
|
1337
|
-
await _analytics.trackEvent(
|
1338
|
-
eventName: '${eventName}_anonymized',
|
1339
|
-
parameters: anonymizedParameters,
|
1340
|
-
);
|
1341
|
-
}
|
1342
|
-
|
1343
|
-
Map<String, dynamic> _anonymizeParameters(Map<String, dynamic>? parameters) {
|
1344
|
-
if (parameters == null) return {};
|
1345
|
-
|
1346
|
-
final anonymized = <String, dynamic>{};
|
1347
|
-
|
1348
|
-
for (final entry in parameters.entries) {
|
1349
|
-
if (_isPersonalData(entry.key)) {
|
1350
|
-
// Hash or remove personal data
|
1351
|
-
anonymized[entry.key] = _hashValue(entry.value.toString());
|
1352
|
-
} else {
|
1353
|
-
anonymized[entry.key] = entry.value;
|
1354
|
-
}
|
1355
|
-
}
|
1356
|
-
|
1357
|
-
return anonymized;
|
1358
|
-
}
|
1359
|
-
|
1360
|
-
bool _hasConsentForDataTypes(Set<String> requiredTypes) {
|
1361
|
-
return requiredTypes.every((type) => _consentedDataTypes.contains(type));
|
1362
|
-
}
|
1363
|
-
|
1364
|
-
bool _isPersonalData(String key) {
|
1365
|
-
const personalDataFields = {
|
1366
|
-
'user_id',
|
1367
|
-
'email',
|
1368
|
-
'name',
|
1369
|
-
'phone',
|
1370
|
-
'address',
|
1371
|
-
'ip_address',
|
1372
|
-
'device_id',
|
1373
|
-
};
|
1374
|
-
|
1375
|
-
return personalDataFields.contains(key.toLowerCase());
|
1376
|
-
}
|
1377
|
-
|
1378
|
-
String _hashValue(String value) {
|
1379
|
-
return sha256.convert(utf8.encode(value)).toString().substring(0, 8);
|
1380
|
-
}
|
1381
|
-
|
1382
|
-
// Data retention and deletion
|
1383
|
-
Future<void> deleteUserAnalyticsData(String userId) async {
|
1384
|
-
// Request deletion from all analytics services
|
1385
|
-
await _analytics.deleteUserData(userId);
|
1386
|
-
|
1387
|
-
// Track data deletion request for audit
|
1388
|
-
_analytics.trackEvent(
|
1389
|
-
eventName: 'user_data_deletion_requested',
|
1390
|
-
parameters: {
|
1391
|
-
'user_id_hash': _hashValue(userId),
|
1392
|
-
'timestamp': DateTime.now().millisecondsSinceEpoch,
|
1393
|
-
},
|
1394
|
-
);
|
1395
|
-
}
|
1396
|
-
|
1397
|
-
// Data export for portability
|
1398
|
-
Future<Map<String, dynamic>> exportUserAnalyticsData(String userId) async {
|
1399
|
-
// Collect user analytics data from local storage
|
1400
|
-
final userData = await _collectUserAnalyticsData(userId);
|
1401
|
-
|
1402
|
-
return {
|
1403
|
-
'user_id': userId,
|
1404
|
-
'export_timestamp': DateTime.now().millisecondsSinceEpoch,
|
1405
|
-
'data_types': _consentedDataTypes.toList(),
|
1406
|
-
'analytics_data': userData,
|
1407
|
-
};
|
1408
|
-
}
|
1409
|
-
}
|
1410
|
-
|
1411
|
-
// Consent Banner Widget
|
1412
|
-
class ConsentBannerWidget extends StatefulWidget {
|
1413
|
-
final Function(bool analyticsConsent, bool personalizationConsent) onConsentUpdate;
|
1414
|
-
|
1415
|
-
const ConsentBannerWidget({
|
1416
|
-
Key? key,
|
1417
|
-
required this.onConsentUpdate,
|
1418
|
-
}) : super(key: key);
|
1419
|
-
|
1420
|
-
@override
|
1421
|
-
_ConsentBannerWidgetState createState() => _ConsentBannerWidgetState();
|
1422
|
-
}
|
1423
|
-
|
1424
|
-
class _ConsentBannerWidgetState extends State<ConsentBannerWidget> {
|
1425
|
-
bool _analyticsConsent = false;
|
1426
|
-
bool _personalizationConsent = false;
|
1427
|
-
|
1428
|
-
@override
|
1429
|
-
Widget build(BuildContext context) {
|
1430
|
-
return Container(
|
1431
|
-
padding: EdgeInsets.all(16),
|
1432
|
-
decoration: BoxDecoration(
|
1433
|
-
color: Theme.of(context).cardColor,
|
1434
|
-
borderRadius: BorderRadius.circular(8),
|
1435
|
-
boxShadow: [
|
1436
|
-
BoxShadow(
|
1437
|
-
color: Colors.black26,
|
1438
|
-
blurRadius: 4,
|
1439
|
-
offset: Offset(0, 2),
|
1440
|
-
),
|
1441
|
-
],
|
1442
|
-
),
|
1443
|
-
child: Column(
|
1444
|
-
mainAxisSize: MainAxisSize.min,
|
1445
|
-
children: [
|
1446
|
-
Text(
|
1447
|
-
'Privacy Preferences',
|
1448
|
-
style: Theme.of(context).textTheme.titleLarge,
|
1449
|
-
),
|
1450
|
-
SizedBox(height: 16),
|
1451
|
-
CheckboxListTile(
|
1452
|
-
title: Text('Analytics'),
|
1453
|
-
subtitle: Text('Help us improve the app with anonymous usage data'),
|
1454
|
-
value: _analyticsConsent,
|
1455
|
-
onChanged: (value) => setState(() => _analyticsConsent = value ?? false),
|
1456
|
-
),
|
1457
|
-
CheckboxListTile(
|
1458
|
-
title: Text('Personalization'),
|
1459
|
-
subtitle: Text('Personalize your experience with your data'),
|
1460
|
-
value: _personalizationConsent,
|
1461
|
-
onChanged: (value) => setState(() => _personalizationConsent = value ?? false),
|
1462
|
-
),
|
1463
|
-
SizedBox(height: 16),
|
1464
|
-
Row(
|
1465
|
-
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
1466
|
-
children: [
|
1467
|
-
ElevatedButton(
|
1468
|
-
onPressed: () {
|
1469
|
-
widget.onConsentUpdate(_analyticsConsent, _personalizationConsent);
|
1470
|
-
Navigator.of(context).pop();
|
1471
|
-
},
|
1472
|
-
child: Text('Save Preferences'),
|
1473
|
-
),
|
1474
|
-
TextButton(
|
1475
|
-
onPressed: () => Navigator.of(context).pop(),
|
1476
|
-
child: Text('Cancel'),
|
1477
|
-
),
|
1478
|
-
],
|
1479
|
-
),
|
1480
|
-
],
|
1481
|
-
),
|
1482
|
-
);
|
1483
|
-
}
|
1484
|
-
}
|
1485
|
-
```
|
1486
|
-
|
1487
|
-
I'm ready to implement comprehensive mobile analytics solutions that provide deep insights into user behavior and app performance while maintaining strict privacy compliance. Let me know what analytics areas you'd like me to focus on!
|