Skip to content

Commit e5e9705

Browse files
Add comprehensive build/test/layout guide to copilot-instructions.md (#207)
Co-authored-by: jaredmixpanel <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]>
1 parent 6ce6dd4 commit e5e9705

File tree

1 file changed

+202
-143
lines changed

1 file changed

+202
-143
lines changed

.github/copilot-instructions.md

Lines changed: 202 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,233 @@
1-
# Project Coding Standards for AI Assistance
1+
# Mixpanel Flutter SDK - Copilot Agent Guide
22

3-
> These instructions are automatically included in every GitHub Copilot interaction. They represent our most critical patterns and conventions for the Mixpanel Flutter SDK.
3+
> Complete operational guide for working efficiently with the Mixpanel Flutter SDK codebase.
44
5-
## Core Principles
5+
## Repository Overview
66

7-
1. **Input Validation First**: All user inputs must be validated before platform channel calls
8-
- String inputs validated with `_MixpanelHelper.isValidString()`
9-
- Prevent crashes at the API boundary
7+
**What**: Official Flutter SDK for Mixpanel Analytics - wraps native iOS/Android/Web SDKs with unified Dart API
8+
**Size**: ~25 source files, 1.4GB total (includes dependencies and build artifacts)
9+
**Languages**: Dart (SDK), Java (Android), Swift (iOS), JavaScript (Web)
10+
**Runtime**: Flutter 3.16.0, Dart 3.2.0, Java 17, Swift 5.0
1011

11-
2. **Fail Silently with Logging**: Never throw exceptions to calling code
12-
- Log errors using `developer.log()` with 'Mixpanel' name
13-
- Return gracefully on validation failures
12+
## Quick Start - Essential Commands
1413

15-
3. **Platform Channel Consistency**: All native calls follow exact same pattern
16-
- Method name must match across Dart and native code
17-
- Arguments always in `Map<String, dynamic>` format
14+
**ALWAYS run these commands in order. Commands must succeed before proceeding.**
1815

19-
4. **Type Safety**: Handle cross-platform type differences explicitly
20-
- Mobile: MixpanelMessageCodec handles DateTime/Uri
21-
- Web: Use `safeJsify()` for JavaScript compatibility
16+
### 1. Install Dependencies (REQUIRED FIRST)
17+
```bash
18+
# From project root - ALWAYS run this first
19+
flutter pub get
2220

23-
## Flutter SDK Guidelines
21+
# For example app (if working with integration tests)
22+
cd example && flutter pub get && cd ..
23+
```
24+
**Time**: ~30 seconds. **Must complete** before any other command.
2425

25-
### Method Patterns
26-
All public methods MUST follow this exact structure:
27-
```dart
28-
Future<void> methodName(String requiredParam, [Map<String, dynamic>? optionalParam]) async {
29-
if (!_MixpanelHelper.isValidString(requiredParam)) {
30-
developer.log('`methodName` failed: requiredParam cannot be blank', name: 'Mixpanel');
31-
return;
32-
}
33-
34-
await _channel.invokeMethod<void>('methodName', <String, dynamic>{
35-
'requiredParam': requiredParam,
36-
'optionalParam': optionalParam ?? {},
37-
});
38-
}
26+
### 2. Run Tests
27+
```bash
28+
# Run all unit tests
29+
flutter test
3930
```
31+
**Time**: ~5 seconds. **Expected**: All tests pass. The SDK has comprehensive test coverage.
4032

41-
### Naming Conventions
42-
- **Methods**: camelCase with action verbs (`track`, `registerSuperProperties`, `getPeople`)
43-
- **Parameters**: Descriptive names (`eventName`, `distinctId`, `properties`)
44-
- **Maps**: Always named `properties` or `superProperties` for consistency
45-
46-
### Platform Channel Rules
47-
When invoking platform methods, you MUST:
48-
1. Use exact method name matching between Dart and native
49-
```dart
50-
await _channel.invokeMethod<void>('track', args); // 'track' must exist in native
51-
```
52-
53-
2. Structure arguments as flat maps
54-
```dart
55-
<String, dynamic>{
56-
'eventName': eventName,
57-
'properties': properties ?? {},
58-
}
59-
```
60-
61-
3. Handle optional parameters with `?? {}`
62-
```dart
63-
'properties': properties ?? {}, // Never pass null
64-
```
65-
66-
## Code Generation Rules
67-
68-
When generating code, you MUST:
69-
70-
1. Validate all string inputs before use
71-
```dart
72-
if (!_MixpanelHelper.isValidString(input)) {
73-
developer.log('`method` failed: input cannot be blank', name: 'Mixpanel');
74-
return;
75-
}
76-
```
77-
78-
2. Return Future<void> for all public methods
79-
```dart
80-
Future<void> methodName() async {
81-
// All methods async for platform consistency
82-
}
83-
```
84-
85-
3. Include library metadata in tracking calls
86-
```dart
87-
properties['\$lib_version'] = '2.4.4';
88-
properties['mp_lib'] = 'flutter';
89-
```
90-
91-
When generating code, NEVER:
92-
- Throw exceptions from public methods
93-
- Pass null to platform channels (use `?? {}`)
94-
- Create synchronous public methods
95-
- Skip input validation
96-
97-
## Testing Requirements
98-
99-
Every test must:
100-
- Use descriptive test names: `test('should fail silently when eventName is empty')`
101-
- Verify platform channel calls with `isMethodCall` matcher
102-
- Test both success and validation failure cases
33+
### 3. Lint/Analyze Code
34+
```bash
35+
# Analyze Dart code (will show ~70 info-level warnings - this is normal)
36+
flutter analyze --no-pub --no-current-package --no-fatal-infos lib
37+
```
38+
**Expected warnings**: Style suggestions (unnecessary_this, prefer_const, etc.) - NOT errors.
39+
**Time**: <1 second
10340

104-
```dart
105-
test('tracks event with properties', () async {
106-
await mixpanel.track('Event', properties: {'key': 'value'});
107-
expect(
108-
methodCall,
109-
isMethodCall(
110-
'track',
111-
arguments: <String, dynamic>{
112-
'eventName': 'Event',
113-
'properties': {'key': 'value'},
114-
},
115-
),
116-
);
117-
});
41+
### 4. Build Integration Tests
42+
```bash
43+
# Android (from example directory)
44+
cd example && flutter build apk --debug
45+
46+
# iOS (from example directory, macOS only)
47+
cd example && flutter build ios --debug --simulator --no-codesign
11848
```
49+
**Android Time**: ~3 minutes first run, ~1 minute incremental
50+
**iOS Time**: ~5 minutes (requires CocoaPods: `cd example/ios && pod repo update`)
11951

120-
## Documentation Standards
52+
## Project Structure
12153

122-
- Public methods need dartdoc with parameter descriptions
123-
- Use `///` for public API documentation
124-
- Include parameter constraints in docs
125-
- No redundant comments in implementation
54+
### Core SDK Files
55+
```
56+
lib/
57+
├── mixpanel_flutter.dart # Main SDK - Primary API
58+
├── mixpanel_flutter_web.dart # Web implementation
59+
├── codec/
60+
│ └── mixpanel_message_codec.dart # Custom type serialization
61+
└── web/
62+
└── mixpanel_js_bindings.dart # JavaScript interop
63+
```
12664

127-
```dart
128-
/// Tracks an event with optional properties.
129-
///
130-
/// * [eventName] The name of the event to track. Cannot be empty.
131-
/// * [properties] Optional properties to include with the event.
132-
Future<void> track(String eventName, [Map<String, dynamic>? properties]) async {
65+
### Native Platform Code
66+
```
67+
android/
68+
├── build.gradle # Android config (SDK 34, Java 17)
69+
└── src/main/java/com/mixpanel/mixpanel_flutter/
70+
├── MixpanelFlutterPlugin.java # Android platform channel
71+
├── MixpanelMessageCodec.java # Type serialization
72+
└── MixpanelFlutterHelper.java # Validation helpers
73+
74+
ios/
75+
├── mixpanel_flutter.podspec # iOS package (Mixpanel-swift 5.1.0)
76+
└── Classes/
77+
├── SwiftMixpanelFlutterPlugin.swift # iOS platform channel
78+
└── MixpanelTypeHandler.swift # Type serialization
79+
```
80+
81+
### Tests
82+
```
83+
test/
84+
├── mixpanel_flutter_test.dart # Main test suite
85+
└── mixpanel_flutter_web_unit_test.dart # Web-specific tests
86+
```
87+
88+
### Configuration Files
89+
- `pubspec.yaml` - Flutter package config, dependencies
90+
- `analysis_options.yaml` - Lints (uses flutter_lints package)
91+
- `.github/workflows/flutter.yml` - CI pipeline (see below)
92+
93+
## Continuous Integration
94+
95+
The GitHub Actions workflow runs **3 jobs** on every PR:
96+
97+
### 1. test-main-code (macOS, ~2 min)
98+
```bash
99+
flutter pub get
100+
flutter test
101+
flutter analyze --no-pub --no-current-package --no-fatal-infos lib
102+
```
103+
104+
### 2. test-android-integration (macOS, ~3 min)
105+
```bash
106+
cd example && flutter build apk
133107
```
134108

135-
## Security and Performance
109+
### 3. test-ios-integration (macOS, ~5 min)
110+
```bash
111+
cd example
112+
flutter clean
113+
flutter pub get
114+
cd ios && pod repo update && cd ..
115+
flutter build ios --debug --simulator --no-codesign
116+
```
117+
118+
**To replicate CI locally**, run all three command sequences above in order.
119+
120+
## Common Build Issues & Solutions
136121

137-
ALWAYS:
138-
- Validate inputs at SDK boundaries
139-
- Sanitize data before sending to native platforms
140-
- Log errors without exposing sensitive data
122+
### Issue: "flutter: command not found"
123+
- **Fix**: Install Flutter 3.16.0 from https://flutter.dev/docs/get-started/install
141124

142-
NEVER:
143-
- Log user data or event properties in error messages
144-
- Trust client inputs without validation
145-
- Make synchronous platform channel calls
125+
### Issue: Android build fails with SDK version error
126+
- **Expected**: Warning about SDK 34 is normal (plugin requires it, example uses 33)
127+
- **Fix**: The build will auto-download SDK 33 and succeed
146128

147-
## Type Handling Matrix
129+
### Issue: iOS build fails with CocoaPods error
130+
- **Fix**: Run `cd example/ios && pod repo update` before building
148131

149-
| Type | Mobile | Web |
150-
|------|---------|-----|
151-
| String | Direct pass | Direct pass |
152-
| num/bool | Direct pass | Direct pass |
153-
| DateTime | MixpanelMessageCodec | Convert to ISO string |
154-
| Uri | MixpanelMessageCodec | Convert to string |
155-
| Map | Direct pass | `safeJsify()` |
156-
| List | Direct pass | `safeJsify()` |
132+
### Issue: "Gradle task assembleDebug" timeout
133+
- **Expected**: First Android build takes 2-3 minutes
134+
- **Solution**: Use `initial_wait: 180` for async commands
157135

158-
## Platform-Specific Patterns
136+
### Issue: Tests fail after code changes
137+
- **Cause**: Platform channel method name mismatch
138+
- **Fix**: Ensure method names match exactly in Dart + Java/Swift + Web
159139

160-
### Web Implementation
140+
## Critical Coding Patterns
141+
142+
**ALWAYS follow these patterns when modifying SDK code:**
143+
144+
### 1. Input Validation Pattern (MANDATORY)
161145
```dart
162-
if (kIsWeb) {
163-
return WebImplementation.method(safeJsify(properties));
146+
Future<void> methodName(String param) async {
147+
if (!_MixpanelHelper.isValidString(param)) {
148+
developer.log('`methodName` failed: param cannot be blank', name: 'Mixpanel');
149+
return; // Fail silently - NEVER throw exceptions
150+
}
151+
await _channel.invokeMethod<void>('methodName', {'param': param});
164152
}
165153
```
166154

167-
### Mobile Implementation
155+
### 2. Platform Channel Rules
156+
- Method names MUST match exactly: Dart ↔ Java/Swift/Web
157+
- Arguments ALWAYS as `Map<String, dynamic>`
158+
- Optional maps use `?? {}` - NEVER pass null
159+
- All methods return `Future<void>` for consistency
160+
161+
### 3. Type Handling
162+
- **Mobile**: MixpanelMessageCodec auto-handles DateTime/Uri
163+
- **Web**: Use `safeJsify()` for complex types
164+
165+
### 4. Testing Requirements
166+
Every method MUST have tests:
168167
```dart
169-
return await _channel.invokeMethod<void>('method', args);
168+
test('methodName should invoke platform method', () async {
169+
await mixpanel.methodName('param');
170+
expect(methodCalls, hasLength(1));
171+
expect(methodCalls[0], isMethodCall('methodName',
172+
arguments: {'param': 'param'}));
173+
});
174+
175+
test('methodName should fail silently on invalid input', () async {
176+
await mixpanel.methodName(''); // Empty string
177+
expect(methodCalls, isEmpty); // No platform call made
178+
});
170179
```
171180

172-
## Additional Resources
181+
## Adding New Features - Checklist
182+
183+
When adding a new SDK method:
184+
1. ✅ Add to `lib/mixpanel_flutter.dart` with validation
185+
2. ✅ Implement in `android/.../MixpanelFlutterPlugin.java`
186+
3. ✅ Implement in `ios/.../SwiftMixpanelFlutterPlugin.swift`
187+
4. ✅ Implement in `lib/mixpanel_flutter_web.dart`
188+
5. ✅ Add tests to `test/mixpanel_flutter_test.dart`
189+
6. ✅ Run `flutter test` - MUST pass all tests
190+
7. ✅ Run `flutter analyze` - check for new errors
191+
8. ✅ Build example app to verify integration
192+
193+
## File Organization
194+
195+
**NEVER modify**:
196+
- `build/` - Build artifacts (gitignored)
197+
- `.dart_tool/` - Flutter tooling cache
198+
- `example/pubspec.lock` - Auto-generated
199+
200+
**Config files to update when**:
201+
- `pubspec.yaml` - Adding dependencies only
202+
- `ios/mixpanel_flutter.podspec` - iOS SDK version bump
203+
- `android/build.gradle` - Android SDK version bump
204+
205+
## Performance Notes
206+
207+
- `flutter pub get`: 30 seconds
208+
- `flutter test`: 5 seconds
209+
- `flutter analyze`: <1 second
210+
- Example Android build: 3 min (first), 1 min (incremental)
211+
- Example iOS build: 5 min (requires `pod repo update`)
212+
213+
## Dependencies
214+
215+
**Production**:
216+
- Mixpanel Android SDK 8.2.0 (in `android/build.gradle`)
217+
- Mixpanel-swift 5.1.0 (in `ios/mixpanel_flutter.podspec`)
218+
- Mixpanel JS (loaded from CDN in web/index.html)
219+
220+
**Dev**:
221+
- flutter_lints 3.0.0 - Linting rules
222+
- flutter_test - Testing framework
223+
224+
## Validation Checklist Before Committing
225+
226+
1.`flutter pub get` - Must succeed
227+
2.`flutter test` - All tests pass
228+
3.`flutter analyze lib` - No new errors (~70 infos OK)
229+
4. ✅ Check method names match across all platforms
230+
5. ✅ Verify input validation exists for all public methods
231+
6. ✅ Confirm tests added for new functionality
173232

174-
For architectural questions or complex refactoring needs, Claude Code CLI (`cc`) provides comprehensive context about this SDK's patterns and implementation details.
233+
**Trust these instructions.** Only search/explore if information is incomplete or incorrect. This guide covers 90% of common scenarios.

0 commit comments

Comments
 (0)