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>

+6
.env.dev
···
# When false, hostedByDID must match the community handle domain
SKIP_DID_WEB_VERIFICATION=true
+
# Authentication: Skip JWT signature verification for local development (Phase 1)
+
# IMPORTANT: Set to false in production for full signature verification
+
# When true, only parses JWT without verifying signature (trusts any valid JWT format)
+
# When false, verifies JWT signature against issuer's JWKS
+
AUTH_SKIP_VERIFY=true
+
# Logging
LOG_LEVEL=debug
LOG_ENABLED=true
+2 -1
.gitignore
···
*.temp
# Build artifacts
-
/validate-lexicon
+
/validate-lexicon
+
/bin/
+20 -3
Makefile
···
@go build -o server ./cmd/server
@echo "$(GREEN)✓ Build complete: ./server$(RESET)"
-
run: ## Run the Coves server (requires database running)
-
@echo "$(GREEN)Starting Coves server...$(RESET)"
-
@go run ./cmd/server
+
run: ## Run the Coves server with dev environment (requires database running)
+
@./scripts/dev-run.sh
##@ Cleanup
···
quick-restart: ## Quick restart of development stack (keeps data)
@make dev-down
@make dev-up
+
+
##@ Mobile Testing
+
+
mobile-setup: ## Setup Android port forwarding for USB-connected devices (recommended)
+
@echo "$(CYAN)Setting up Android mobile testing environment...$(RESET)"
+
@./scripts/setup-mobile-ports.sh
+
+
mobile-reset: ## Remove all Android port forwarding
+
@echo "$(YELLOW)Removing Android port forwarding...$(RESET)"
+
@adb reverse --remove-all || echo "$(YELLOW)No device connected$(RESET)"
+
@echo "$(GREEN)✓ Port forwarding removed$(RESET)"
+
+
ngrok-up: ## Start ngrok tunnels (for iOS or WiFi testing - requires paid plan for 3 tunnels)
+
@echo "$(GREEN)Starting ngrok tunnels for mobile testing...$(RESET)"
+
@./scripts/start-ngrok.sh
+
+
ngrok-down: ## Stop all ngrok tunnels
+
@./scripts/stop-ngrok.sh
##@ Utilities
+7 -8
docker-compose.dev.yml
···
image: ghcr.io/bluesky-social/pds:latest
container_name: coves-dev-pds
ports:
-
- "3001:3000" # PDS XRPC API (avoiding production PDS on :3000)
+
- "3001:3001" # PDS XRPC API (avoiding production PDS on :3000)
environment:
# PDS Configuration
PDS_HOSTNAME: ${PDS_HOSTNAME:-localhost}
-
PDS_PORT: 3000
+
PDS_PORT: 3001 # Match external port for correct DID registration
PDS_DATA_DIRECTORY: /pds
PDS_BLOBSTORE_DISK_LOCATION: /pds/blocks
PDS_DID_PLC_URL: ${PDS_DID_PLC_URL:-https://plc.directory}
···
networks:
- coves-dev
healthcheck:
-
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/xrpc/_health"]
+
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3001/xrpc/_health"]
interval: 10s
timeout: 5s
retries: 5
···
- "6009:6009" # Metrics endpoint
environment:
# Point Jetstream at local PDS firehose
-
JETSTREAM_WS_URL: ws://pds:3000/xrpc/com.atproto.sync.subscribeRepos
+
JETSTREAM_WS_URL: ws://pds:3001/xrpc/com.atproto.sync.subscribeRepos
# Server configuration
JETSTREAM_LISTEN_ADDR: ":6008"
···
depends_on:
pds:
condition: service_healthy
+
# Health check disabled for dev - container has no HTTP clients installed
+
# Jetstream logs show it connects and runs successfully
healthcheck:
-
test: ["CMD", "wget", "--spider", "-q", "http://localhost:6009/metrics"]
-
interval: 10s
-
timeout: 5s
-
retries: 5
+
disable: true
profiles:
- jetstream
+14
scripts/dev-run.sh
···
+
#!/bin/bash
+
# Development server runner - loads .env.dev before starting
+
+
set -a # automatically export all variables
+
source .env.dev
+
set +a
+
+
echo "🚀 Starting Coves server in DEV mode..."
+
echo " IS_DEV_ENV: $IS_DEV_ENV"
+
echo " PLC_DIRECTORY_URL: $PLC_DIRECTORY_URL"
+
echo " JETSTREAM_URL: $JETSTREAM_URL"
+
echo ""
+
+
go run ./cmd/server
+68
scripts/setup-mobile-ports.sh
···
+
#!/bin/bash
+
# Setup adb reverse port forwarding for mobile testing
+
# This allows the mobile app to access localhost services on the dev machine
+
+
set -e
+
+
# Colors
+
GREEN='\033[0;32m'
+
CYAN='\033[0;36m'
+
YELLOW='\033[1;33m'
+
RED='\033[0;31m'
+
NC='\033[0m' # No Color
+
+
echo -e "${CYAN}📱 Setting up Android port forwarding for Coves mobile testing...${NC}"
+
echo ""
+
+
# Check if adb is available
+
if ! command -v adb &> /dev/null; then
+
echo -e "${RED}✗ adb not found${NC}"
+
echo "Install Android SDK Platform Tools: https://developer.android.com/studio/releases/platform-tools"
+
exit 1
+
fi
+
+
# Check if device is connected
+
DEVICES=$(adb devices | grep -v "List" | grep "device$" | wc -l)
+
if [ "$DEVICES" -eq 0 ]; then
+
echo -e "${RED}✗ No Android devices connected${NC}"
+
echo "Connect a device via USB or start an emulator"
+
exit 1
+
fi
+
+
echo -e "${YELLOW}Setting up port forwarding...${NC}"
+
+
# Forward ports from Android device to localhost
+
adb reverse tcp:3000 tcp:3001 # PDS (internal port in DID document)
+
adb reverse tcp:3001 tcp:3001 # PDS (external port)
+
adb reverse tcp:3002 tcp:3002 # PLC Directory
+
adb reverse tcp:8081 tcp:8081 # AppView
+
+
echo ""
+
echo -e "${GREEN}✅ Port forwarding configured successfully!${NC}"
+
echo ""
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo -e "${CYAN} PORT FORWARDING ${NC}"
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo ""
+
echo -e "${GREEN}PDS (3000):${NC} localhost:3001 → device:3000 ${YELLOW}(DID document port)${NC}"
+
echo -e "${GREEN}PDS (3001):${NC} localhost:3001 → device:3001"
+
echo -e "${GREEN}PLC (3002):${NC} localhost:3002 → device:3002"
+
echo -e "${GREEN}AppView (8081):${NC} localhost:8081 → device:8081"
+
echo ""
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo ""
+
echo -e "${CYAN}📱 Next Steps:${NC}"
+
echo ""
+
echo -e "1. Mobile app is already configured for localhost (environment_config.dart)"
+
echo ""
+
echo -e "2. Run mobile app:"
+
echo -e " ${YELLOW}cd /home/bretton/Code/coves-mobile${NC}"
+
echo -e " ${YELLOW}flutter run --dart-define=ENVIRONMENT=local${NC}"
+
echo ""
+
echo -e "3. Login with:"
+
echo -e " Handle: ${CYAN}charlie.local.coves.dev${NC}"
+
echo -e " Password: ${CYAN}charliepass123${NC}"
+
echo ""
+
echo -e "${YELLOW}💡 Note: Port forwarding persists until device disconnects or you run:${NC}"
+
echo -e "${YELLOW} adb reverse --remove-all${NC}"
+
echo ""
+116
scripts/start-ngrok.sh
···
+
#!/bin/bash
+
# Automated ngrok tunnel starter for mobile testing
+
# Starts 3 ngrok tunnels and captures their HTTPS URLs
+
+
set -e
+
+
# Colors
+
GREEN='\033[0;32m'
+
CYAN='\033[0;36m'
+
YELLOW='\033[1;33m'
+
NC='\033[0m' # No Color
+
+
echo -e "${CYAN}🚀 Starting ngrok tunnels for Coves mobile testing...${NC}"
+
echo ""
+
+
# Kill any existing ngrok processes
+
pkill -f "ngrok http" || true
+
sleep 2
+
+
# Start ngrok tunnels using separate processes (simpler, works with any config version)
+
echo -e "${YELLOW}Starting PDS tunnel (port 3001)...${NC}"
+
ngrok http 3001 --log=stdout > /tmp/ngrok-pds.log 2>&1 &
+
sleep 1
+
+
echo -e "${YELLOW}Starting PLC tunnel (port 3002)...${NC}"
+
ngrok http 3002 --log=stdout > /tmp/ngrok-plc.log 2>&1 &
+
sleep 1
+
+
echo -e "${YELLOW}Starting AppView tunnel (port 8081)...${NC}"
+
ngrok http 8081 --log=stdout > /tmp/ngrok-appview.log 2>&1 &
+
+
# Get all PIDs
+
PIDS=$(pgrep -f "ngrok http")
+
NGROK_PID=$PIDS
+
+
# Save PID for cleanup
+
echo "$NGROK_PID" > /tmp/ngrok-pids.txt
+
+
# Wait for ngrok to initialize
+
echo ""
+
echo -e "${YELLOW}Waiting for tunnels to initialize...${NC}"
+
sleep 7
+
+
# Fetch URLs from ngrok API (single API at port 4040)
+
echo ""
+
echo -e "${GREEN}✅ Tunnels started successfully!${NC}"
+
echo ""
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo -e "${CYAN} NGROK TUNNEL URLS ${NC}"
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo ""
+
+
# Get all tunnel info
+
TUNNELS=$(curl -s http://localhost:4040/api/tunnels 2>/dev/null || echo "")
+
+
# Extract URLs by matching port in config.addr
+
PDS_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("3001")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1)
+
PLC_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("3002")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1)
+
APPVIEW_URL=$(echo "$TUNNELS" | jq -r '.tunnels[] | select(.config.addr | contains("8081")) | select(.proto=="https") | .public_url' 2>/dev/null | head -1)
+
+
# Fallback if jq filtering fails - just get first 3 HTTPS URLs
+
if [ -z "$PDS_URL" ] || [ -z "$PLC_URL" ] || [ -z "$APPVIEW_URL" ]; then
+
echo -e "${YELLOW}⚠️ Port-based matching failed, using fallback...${NC}"
+
URLS=($(echo "$TUNNELS" | jq -r '.tunnels[] | select(.proto=="https") | .public_url' 2>/dev/null))
+
PDS_URL=${URLS[0]:-ERROR}
+
PLC_URL=${URLS[1]:-ERROR}
+
APPVIEW_URL=${URLS[2]:-ERROR}
+
fi
+
+
echo -e "${GREEN}PDS (3001):${NC} $PDS_URL"
+
echo -e "${GREEN}PLC (3002):${NC} $PLC_URL"
+
echo -e "${GREEN}AppView (8081):${NC} $APPVIEW_URL"
+
+
echo ""
+
echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}"
+
echo ""
+
+
# Check if any URLs failed
+
if [[ "$PDS_URL" == "ERROR" ]] || [[ "$PLC_URL" == "ERROR" ]] || [[ "$APPVIEW_URL" == "ERROR" ]]; then
+
echo -e "${YELLOW}⚠️ Some tunnels failed to start. Check logs:${NC}"
+
echo " tail -f /tmp/ngrok-pds.log"
+
echo " tail -f /tmp/ngrok-plc.log"
+
echo " tail -f /tmp/ngrok-appview.log"
+
exit 1
+
fi
+
+
# Extract clean URLs (remove https://)
+
PDS_CLEAN=$(echo $PDS_URL | sed 's|https://||')
+
PLC_CLEAN=$(echo $PLC_URL | sed 's|https://||')
+
APPVIEW_CLEAN=$(echo $APPVIEW_URL | sed 's|https://||')
+
+
echo -e "${CYAN}📱 Next Steps:${NC}"
+
echo ""
+
echo -e "1. Update ${YELLOW}coves-mobile/lib/config/environment_config.dart${NC}:"
+
echo ""
+
echo -e "${GREEN}static const local = EnvironmentConfig(${NC}"
+
echo -e "${GREEN} environment: Environment.local,${NC}"
+
echo -e "${GREEN} apiUrl: '$APPVIEW_URL',${NC}"
+
echo -e "${GREEN} handleResolverUrl: '$PDS_URL/xrpc/com.atproto.identity.resolveHandle',${NC}"
+
echo -e "${GREEN} plcDirectoryUrl: '$PLC_URL',${NC}"
+
echo -e "${GREEN});${NC}"
+
echo ""
+
echo -e "2. Run mobile app:"
+
echo -e " ${YELLOW}cd /home/bretton/Code/coves-mobile${NC}"
+
echo -e " ${YELLOW}flutter run --dart-define=ENVIRONMENT=local${NC}"
+
echo ""
+
echo -e "3. Login with:"
+
echo -e " Handle: ${CYAN}bob.local.coves.dev${NC}"
+
echo -e " Password: ${CYAN}bobpass123${NC}"
+
echo ""
+
echo -e "${YELLOW}💡 Tip: Leave this terminal open. Press Ctrl+C to stop tunnels.${NC}"
+
echo -e "${YELLOW} Or run: make ngrok-down${NC}"
+
echo ""
+
+
# Keep script running (can be killed with Ctrl+C or make ngrok-down)
+
wait
+26
scripts/stop-ngrok.sh
···
+
#!/bin/bash
+
# Stop all ngrok tunnels
+
+
# Colors
+
GREEN='\033[0;32m'
+
YELLOW='\033[1;33m'
+
NC='\033[0m'
+
+
echo -e "${YELLOW}Stopping ngrok tunnels...${NC}"
+
+
# Kill processes by PID if available
+
if [ -f /tmp/ngrok-pids.txt ]; then
+
PIDS=$(cat /tmp/ngrok-pids.txt)
+
for pid in $PIDS; do
+
kill $pid 2>/dev/null || true
+
done
+
rm /tmp/ngrok-pids.txt
+
fi
+
+
# Fallback: kill all ngrok processes
+
pkill -f "ngrok http" || true
+
+
# Clean up logs
+
rm -f /tmp/ngrok-*.log
+
+
echo -e "${GREEN}✓ ngrok tunnels stopped${NC}"