Skip to content

Commit e6a33af

Browse files
ndbroadbentclaude
andcommitted
Add OpenAPI client generation and Google Analytics tracking
OpenAPI Integration: - Embed openapi.json from SaaS app in src-tauri/ - Generate type-safe Rust API client at build time (progenitor) - Rewrite upload.rs to use generated client instead of manual types - Add scripts/check_openapi_sync.sh to verify schema is in sync Google Analytics: - Add analytics.ts with GA4 initialization and tracking - Track virtual page views for all screens (permission, selection, progress, etc.) - Track funnel events (permission required, chats loaded, export started/completed/failed) - Configure via VITE_GA_MEASUREMENT_ID environment variable Privacy: - Add "Privacy & Telemetry" section to README - Document what data is collected and what is NOT collected - Be transparent that no chat content or personal data is sent to analytics 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 8f3603b commit e6a33af

File tree

13 files changed

+1771
-101
lines changed

13 files changed

+1771
-101
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Google Analytics 4 Measurement ID
2+
# Get this from: Google Analytics > Admin > Data Streams > Web
3+
# Format: G-XXXXXXXXXX
4+
VITE_GA_MEASUREMENT_ID=

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,28 @@ This project follows strict quality standards:
171171

172172
All checks must pass before committing. Git hooks enforce this automatically.
173173

174+
---
175+
176+
## Privacy & Telemetry
177+
178+
This app collects anonymous usage analytics via Google Analytics to help us improve the user experience.
179+
180+
### What We Collect
181+
182+
- **Screen views**: Which screens you visit (permission, chat selection, progress, success, error)
183+
- **Funnel events**: Whether you complete the export flow, and where drop-offs occur
184+
- **Aggregate counts**: Number of chats loaded, number of chats selected for export
185+
186+
### What We Do NOT Collect
187+
188+
- **No chat content**: Your messages are never sent to analytics
189+
- **No personal data**: No names, phone numbers, or identifiers
190+
- **No contact information**: Your address book data stays on your device
191+
192+
Analytics data helps us understand which parts of the app work well and where users encounter issues.
193+
194+
---
195+
174196
## License
175197

176198
GPL-3.0 - See [LICENSE](LICENSE) for details.

scripts/check_openapi_sync.sh

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/bin/bash
2+
# Check if openapi.json is in sync with the SaaS app
3+
#
4+
# Usage:
5+
# ./scripts/check_openapi_sync.sh # Check against local SaaS
6+
# ./scripts/check_openapi_sync.sh --update # Update from local SaaS
7+
#
8+
# This script is meant to be run from the desktop app directory:
9+
# /path/to/chat_to_map_desktop/
10+
#
11+
# It expects the SaaS app to be at:
12+
# /path/to/chat_to_map_saas/static/openapi.json (after build)
13+
#
14+
# Or in a worktree setup:
15+
# ../static/openapi.json
16+
17+
set -e
18+
19+
# Colors
20+
RED='\033[0;31m'
21+
GREEN='\033[0;32m'
22+
YELLOW='\033[1;33m'
23+
NC='\033[0m'
24+
25+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26+
DESKTOP_ROOT="$(dirname "$SCRIPT_DIR")"
27+
DESKTOP_SCHEMA="$DESKTOP_ROOT/src-tauri/openapi.json"
28+
29+
# Try to find the SaaS openapi.json
30+
# 1. Worktree setup: ../static/openapi.json (desktop is inside saas worktree)
31+
# 2. Sibling repo: ../chat_to_map_saas/static/openapi.json
32+
SAAS_SCHEMA=""
33+
if [[ -f "$DESKTOP_ROOT/../static/openapi.json" ]]; then
34+
SAAS_SCHEMA="$DESKTOP_ROOT/../static/openapi.json"
35+
elif [[ -f "$DESKTOP_ROOT/../../chat_to_map_saas/static/openapi.json" ]]; then
36+
SAAS_SCHEMA="$DESKTOP_ROOT/../../chat_to_map_saas/static/openapi.json"
37+
fi
38+
39+
check_sync() {
40+
if [[ ! -f "$DESKTOP_SCHEMA" ]]; then
41+
echo -e "${RED}Error: Desktop openapi.json not found at $DESKTOP_SCHEMA${NC}"
42+
echo "Run --update to copy it from the SaaS app"
43+
exit 1
44+
fi
45+
46+
if [[ -z "$SAAS_SCHEMA" ]]; then
47+
echo -e "${YELLOW}Warning: SaaS openapi.json not found${NC}"
48+
echo "Expected at:"
49+
echo " - ../static/openapi.json (worktree)"
50+
echo " - ../../chat_to_map_saas/static/openapi.json (sibling)"
51+
echo ""
52+
echo "Build the SaaS app first: cd <saas> && bun run build"
53+
exit 1
54+
fi
55+
56+
if ! diff -q "$DESKTOP_SCHEMA" "$SAAS_SCHEMA" > /dev/null 2>&1; then
57+
echo -e "${RED}Error: openapi.json is out of sync!${NC}"
58+
echo ""
59+
echo "Desktop: $DESKTOP_SCHEMA"
60+
echo "SaaS: $SAAS_SCHEMA"
61+
echo ""
62+
echo "Run: ./scripts/check_openapi_sync.sh --update"
63+
exit 1
64+
fi
65+
66+
echo -e "${GREEN}✅ openapi.json is in sync${NC}"
67+
}
68+
69+
update_schema() {
70+
if [[ -z "$SAAS_SCHEMA" ]]; then
71+
echo -e "${RED}Error: SaaS openapi.json not found${NC}"
72+
echo "Build the SaaS app first: cd <saas> && bun run build"
73+
exit 1
74+
fi
75+
76+
echo "Copying from: $SAAS_SCHEMA"
77+
echo " to: $DESKTOP_SCHEMA"
78+
cp "$SAAS_SCHEMA" "$DESKTOP_SCHEMA"
79+
echo -e "${GREEN}✅ openapi.json updated${NC}"
80+
echo ""
81+
echo "Next steps:"
82+
echo " 1. cargo build --lib # Regenerate Rust types"
83+
echo " 2. cargo test # Verify types compile"
84+
echo " 3. git add src-tauri/openapi.json"
85+
echo " 4. git commit -m 'Update openapi.json from SaaS'"
86+
}
87+
88+
case "${1:-}" in
89+
--update|-u)
90+
update_schema
91+
;;
92+
--help|-h)
93+
echo "Usage: $0 [--update]"
94+
echo ""
95+
echo "Check or update openapi.json sync with SaaS app."
96+
echo ""
97+
echo "Options:"
98+
echo " --update, -u Copy openapi.json from SaaS to desktop"
99+
echo " --help, -h Show this help"
100+
;;
101+
*)
102+
check_sync
103+
;;
104+
esac

0 commit comments

Comments
 (0)