A community based topic aggregation platform built on atproto

feat(dev): add mobile testing infrastructure and environment fixes

- Add mobile testing targets to Makefile (adb port forwarding, ngrok)
- Fix PDS port configuration (3000→3001 for correct DID registration)
- Add AUTH_SKIP_VERIFY flag for local JWT development
- Add scripts for mobile port setup and ngrok tunnels
- Add bin/ to .gitignore for build artifacts

Enables USB-connected Android testing and iOS/WiFi testing via ngrok

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

+259 -12
+6
.env.dev
··· 143 143 # When false, hostedByDID must match the community handle domain 144 144 SKIP_DID_WEB_VERIFICATION=true 145 145 146 + # Authentication: Skip JWT signature verification for local development (Phase 1) 147 + # IMPORTANT: Set to false in production for full signature verification 148 + # When true, only parses JWT without verifying signature (trusts any valid JWT format) 149 + # When false, verifies JWT signature against issuer's JWKS 150 + AUTH_SKIP_VERIFY=true 151 + 146 152 # Logging 147 153 LOG_LEVEL=debug 148 154 LOG_ENABLED=true
+2 -1
.gitignore
··· 45 45 *.temp 46 46 47 47 # Build artifacts 48 - /validate-lexicon 48 + /validate-lexicon 49 + /bin/
+20 -3
Makefile
··· 191 191 @go build -o server ./cmd/server 192 192 @echo "$(GREEN)✓ Build complete: ./server$(RESET)" 193 193 194 - run: ## Run the Coves server (requires database running) 195 - @echo "$(GREEN)Starting Coves server...$(RESET)" 196 - @go run ./cmd/server 194 + run: ## Run the Coves server with dev environment (requires database running) 195 + @./scripts/dev-run.sh 197 196 198 197 ##@ Cleanup 199 198 ··· 225 224 quick-restart: ## Quick restart of development stack (keeps data) 226 225 @make dev-down 227 226 @make dev-up 227 + 228 + ##@ Mobile Testing 229 + 230 + mobile-setup: ## Setup Android port forwarding for USB-connected devices (recommended) 231 + @echo "$(CYAN)Setting up Android mobile testing environment...$(RESET)" 232 + @./scripts/setup-mobile-ports.sh 233 + 234 + mobile-reset: ## Remove all Android port forwarding 235 + @echo "$(YELLOW)Removing Android port forwarding...$(RESET)" 236 + @adb reverse --remove-all || echo "$(YELLOW)No device connected$(RESET)" 237 + @echo "$(GREEN)✓ Port forwarding removed$(RESET)" 238 + 239 + ngrok-up: ## Start ngrok tunnels (for iOS or WiFi testing - requires paid plan for 3 tunnels) 240 + @echo "$(GREEN)Starting ngrok tunnels for mobile testing...$(RESET)" 241 + @./scripts/start-ngrok.sh 242 + 243 + ngrok-down: ## Stop all ngrok tunnels 244 + @./scripts/stop-ngrok.sh 228 245 229 246 ##@ Utilities 230 247
+7 -8
docker-compose.dev.yml
··· 64 64 image: ghcr.io/bluesky-social/pds:latest 65 65 container_name: coves-dev-pds 66 66 ports: 67 - - "3001:3000" # PDS XRPC API (avoiding production PDS on :3000) 67 + - "3001:3001" # PDS XRPC API (avoiding production PDS on :3000) 68 68 environment: 69 69 # PDS Configuration 70 70 PDS_HOSTNAME: ${PDS_HOSTNAME:-localhost} 71 - PDS_PORT: 3000 71 + PDS_PORT: 3001 # Match external port for correct DID registration 72 72 PDS_DATA_DIRECTORY: /pds 73 73 PDS_BLOBSTORE_DISK_LOCATION: /pds/blocks 74 74 PDS_DID_PLC_URL: ${PDS_DID_PLC_URL:-https://plc.directory} ··· 101 101 networks: 102 102 - coves-dev 103 103 healthcheck: 104 - test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/xrpc/_health"] 104 + test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001/xrpc/_health"] 105 105 interval: 10s 106 106 timeout: 5s 107 107 retries: 5 ··· 128 128 - "6009:6009" # Metrics endpoint 129 129 environment: 130 130 # Point Jetstream at local PDS firehose 131 - JETSTREAM_WS_URL: ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos 131 + JETSTREAM_WS_URL: ws://pds:3001/xrpc/com.atproto.sync.subscribeRepos 132 132 133 133 # Server configuration 134 134 JETSTREAM_LISTEN_ADDR: ":6008" ··· 154 154 depends_on: 155 155 pds: 156 156 condition: service_healthy 157 + # Health check disabled for dev - container has no HTTP clients installed 158 + # Jetstream logs show it connects and runs successfully 157 159 healthcheck: 158 - test: ["CMD", "wget", "--spider", "-q", "http://localhost:6009/metrics"] 159 - interval: 10s 160 - timeout: 5s 161 - retries: 5 160 + disable: true 162 161 profiles: 163 162 - jetstream 164 163
+14
scripts/dev-run.sh
··· 1 + #!/bin/bash 2 + # Development server runner - loads .env.dev before starting 3 + 4 + set -a # automatically export all variables 5 + source .env.dev 6 + set +a 7 + 8 + echo "🚀 Starting Coves server in DEV mode..." 9 + echo " IS_DEV_ENV: $IS_DEV_ENV" 10 + echo " PLC_DIRECTORY_URL: $PLC_DIRECTORY_URL" 11 + echo " JETSTREAM_URL: $JETSTREAM_URL" 12 + echo "" 13 + 14 + go run ./cmd/server
+68
scripts/setup-mobile-ports.sh
··· 1 + #!/bin/bash 2 + # Setup adb reverse port forwarding for mobile testing 3 + # This allows the mobile app to access localhost services on the dev machine 4 + 5 + set -e 6 + 7 + # Colors 8 + GREEN='\033[0;32m' 9 + CYAN='\033[0;36m' 10 + YELLOW='\033[1;33m' 11 + RED='\033[0;31m' 12 + NC='\033[0m' # No Color 13 + 14 + echo -e "${CYAN}📱 Setting up Android port forwarding for Coves mobile testing...${NC}" 15 + echo "" 16 + 17 + # Check if adb is available 18 + if ! command -v adb &> /dev/null; then 19 + echo -e "${RED}✗ adb not found${NC}" 20 + echo "Install Android SDK Platform Tools: https://developer.android.com/studio/releases/platform-tools" 21 + exit 1 22 + fi 23 + 24 + # Check if device is connected 25 + DEVICES=$(adb devices | grep -v "List" | grep "device$" | wc -l) 26 + if [ "$DEVICES" -eq 0 ]; then 27 + echo -e "${RED}✗ No Android devices connected${NC}" 28 + echo "Connect a device via USB or start an emulator" 29 + exit 1 30 + fi 31 + 32 + echo -e "${YELLOW}Setting up port forwarding...${NC}" 33 + 34 + # Forward ports from Android device to localhost 35 + adb reverse tcp:3000 tcp:3001 # PDS (internal port in DID document) 36 + adb reverse tcp:3001 tcp:3001 # PDS (external port) 37 + adb reverse tcp:3002 tcp:3002 # PLC Directory 38 + adb reverse tcp:8081 tcp:8081 # AppView 39 + 40 + echo "" 41 + echo -e "${GREEN}✅ Port forwarding configured successfully!${NC}" 42 + echo "" 43 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 44 + echo -e "${CYAN} PORT FORWARDING ${NC}" 45 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 46 + echo "" 47 + echo -e "${GREEN}PDS (3000):${NC} localhost:3001 → device:3000 ${YELLOW}(DID document port)${NC}" 48 + echo -e "${GREEN}PDS (3001):${NC} localhost:3001 → device:3001" 49 + echo -e "${GREEN}PLC (3002):${NC} localhost:3002 → device:3002" 50 + echo -e "${GREEN}AppView (8081):${NC} localhost:8081 → device:8081" 51 + echo "" 52 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 53 + echo "" 54 + echo -e "${CYAN}📱 Next Steps:${NC}" 55 + echo "" 56 + echo -e "1. Mobile app is already configured for localhost (environment_config.dart)" 57 + echo "" 58 + echo -e "2. Run mobile app:" 59 + echo -e " ${YELLOW}cd /home/bretton/Code/coves-mobile${NC}" 60 + echo -e " ${YELLOW}flutter run --dart-define=ENVIRONMENT=local${NC}" 61 + echo "" 62 + echo -e "3. Login with:" 63 + echo -e " Handle: ${CYAN}charlie.local.coves.dev${NC}" 64 + echo -e " Password: ${CYAN}charliepass123${NC}" 65 + echo "" 66 + echo -e "${YELLOW}💡 Note: Port forwarding persists until device disconnects or you run:${NC}" 67 + echo -e "${YELLOW} adb reverse --remove-all${NC}" 68 + echo ""
+116
scripts/start-ngrok.sh
··· 1 + #!/bin/bash 2 + # Automated ngrok tunnel starter for mobile testing 3 + # Starts 3 ngrok tunnels and captures their HTTPS URLs 4 + 5 + set -e 6 + 7 + # Colors 8 + GREEN='\033[0;32m' 9 + CYAN='\033[0;36m' 10 + YELLOW='\033[1;33m' 11 + NC='\033[0m' # No Color 12 + 13 + echo -e "${CYAN}🚀 Starting ngrok tunnels for Coves mobile testing...${NC}" 14 + echo "" 15 + 16 + # Kill any existing ngrok processes 17 + pkill -f "ngrok http" || true 18 + sleep 2 19 + 20 + # Start ngrok tunnels using separate processes (simpler, works with any config version) 21 + echo -e "${YELLOW}Starting PDS tunnel (port 3001)...${NC}" 22 + ngrok http 3001 --log=stdout > /tmp/ngrok-pds.log 2>&1 & 23 + sleep 1 24 + 25 + echo -e "${YELLOW}Starting PLC tunnel (port 3002)...${NC}" 26 + ngrok http 3002 --log=stdout > /tmp/ngrok-plc.log 2>&1 & 27 + sleep 1 28 + 29 + echo -e "${YELLOW}Starting AppView tunnel (port 8081)...${NC}" 30 + ngrok http 8081 --log=stdout > /tmp/ngrok-appview.log 2>&1 & 31 + 32 + # Get all PIDs 33 + PIDS=$(pgrep -f "ngrok http") 34 + NGROK_PID=$PIDS 35 + 36 + # Save PID for cleanup 37 + echo "$NGROK_PID" > /tmp/ngrok-pids.txt 38 + 39 + # Wait for ngrok to initialize 40 + echo "" 41 + echo -e "${YELLOW}Waiting for tunnels to initialize...${NC}" 42 + sleep 7 43 + 44 + # Fetch URLs from ngrok API (single API at port 4040) 45 + echo "" 46 + echo -e "${GREEN}✅ Tunnels started successfully!${NC}" 47 + echo "" 48 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 49 + echo -e "${CYAN} NGROK TUNNEL URLS ${NC}" 50 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 51 + echo "" 52 + 53 + # Get all tunnel info 54 + TUNNELS=$(curl -s http://localhost:4040/api/tunnels 2>/dev/null || echo "") 55 + 56 + # Extract URLs by matching port in config.addr 57 + PDS_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("3001")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1) 58 + PLC_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("3002")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1) 59 + APPVIEW_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("8081")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1) 60 + 61 + # Fallback if jq filtering fails - just get first 3 HTTPS URLs 62 + if [ -z "$PDS_URL" ] || [ -z "$PLC_URL" ] || [ -z "$APPVIEW_URL" ]; then 63 + echo -e "${YELLOW}⚠️ Port-based matching failed, using fallback...${NC}" 64 + URLS=($(echo "$TUNNELS" | jq -r '.tunnels[] | select(.proto=="https") | .public_url' 2>/dev/null)) 65 + PDS_URL=${URLS[0]:-ERROR} 66 + PLC_URL=${URLS[1]:-ERROR} 67 + APPVIEW_URL=${URLS[2]:-ERROR} 68 + fi 69 + 70 + echo -e "${GREEN}PDS (3001):${NC} $PDS_URL" 71 + echo -e "${GREEN}PLC (3002):${NC} $PLC_URL" 72 + echo -e "${GREEN}AppView (8081):${NC} $APPVIEW_URL" 73 + 74 + echo "" 75 + echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" 76 + echo "" 77 + 78 + # Check if any URLs failed 79 + if [[ "$PDS_URL" == "ERROR" ]] || [[ "$PLC_URL" == "ERROR" ]] || [[ "$APPVIEW_URL" == "ERROR" ]]; then 80 + echo -e "${YELLOW}⚠️ Some tunnels failed to start. Check logs:${NC}" 81 + echo " tail -f /tmp/ngrok-pds.log" 82 + echo " tail -f /tmp/ngrok-plc.log" 83 + echo " tail -f /tmp/ngrok-appview.log" 84 + exit 1 85 + fi 86 + 87 + # Extract clean URLs (remove https://) 88 + PDS_CLEAN=$(echo $PDS_URL | sed 's|https://||') 89 + PLC_CLEAN=$(echo $PLC_URL | sed 's|https://||') 90 + APPVIEW_CLEAN=$(echo $APPVIEW_URL | sed 's|https://||') 91 + 92 + echo -e "${CYAN}📱 Next Steps:${NC}" 93 + echo "" 94 + echo -e "1. Update ${YELLOW}coves-mobile/lib/config/environment_config.dart${NC}:" 95 + echo "" 96 + echo -e "${GREEN}static const local = EnvironmentConfig(${NC}" 97 + echo -e "${GREEN} environment: Environment.local,${NC}" 98 + echo -e "${GREEN} apiUrl: '$APPVIEW_URL',${NC}" 99 + echo -e "${GREEN} handleResolverUrl: '$PDS_URL/xrpc/com.atproto.identity.resolveHandle',${NC}" 100 + echo -e "${GREEN} plcDirectoryUrl: '$PLC_URL',${NC}" 101 + echo -e "${GREEN});${NC}" 102 + echo "" 103 + echo -e "2. Run mobile app:" 104 + echo -e " ${YELLOW}cd /home/bretton/Code/coves-mobile${NC}" 105 + echo -e " ${YELLOW}flutter run --dart-define=ENVIRONMENT=local${NC}" 106 + echo "" 107 + echo -e "3. Login with:" 108 + echo -e " Handle: ${CYAN}bob.local.coves.dev${NC}" 109 + echo -e " Password: ${CYAN}bobpass123${NC}" 110 + echo "" 111 + echo -e "${YELLOW}💡 Tip: Leave this terminal open. Press Ctrl+C to stop tunnels.${NC}" 112 + echo -e "${YELLOW} Or run: make ngrok-down${NC}" 113 + echo "" 114 + 115 + # Keep script running (can be killed with Ctrl+C or make ngrok-down) 116 + wait
+26
scripts/stop-ngrok.sh
··· 1 + #!/bin/bash 2 + # Stop all ngrok tunnels 3 + 4 + # Colors 5 + GREEN='\033[0;32m' 6 + YELLOW='\033[1;33m' 7 + NC='\033[0m' 8 + 9 + echo -e "${YELLOW}Stopping ngrok tunnels...${NC}" 10 + 11 + # Kill processes by PID if available 12 + if [ -f /tmp/ngrok-pids.txt ]; then 13 + PIDS=$(cat /tmp/ngrok-pids.txt) 14 + for pid in $PIDS; do 15 + kill $pid 2>/dev/null || true 16 + done 17 + rm /tmp/ngrok-pids.txt 18 + fi 19 + 20 + # Fallback: kill all ngrok processes 21 + pkill -f "ngrok http" || true 22 + 23 + # Clean up logs 24 + rm -f /tmp/ngrok-*.log 25 + 26 + echo -e "${GREEN}✓ ngrok tunnels stopped${NC}"