Files

4.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Commands

Development (full app)

bash scripts/dev.sh

Builds backend, desktop, regenerates Wails bindings, type-checks frontend, then starts wails dev with hot reload.

Build for production

bash scripts/build.sh

Per-component build/check

# Backend
cd backend-go && go build ./...

# Desktop (Go)
cd desktop && go build ./...

# Frontend type-check only
cd frontend-react && npx tsc -b --noEmit

# Frontend bundle (outputs to desktop/frontend/dist/)
cd frontend-react && npm run build

# Wails desktop binary
cd desktop && export PATH="$PATH:$(go env GOPATH)/bin" && wails build

# Android SDK
cd android-sdk && ./gradlew :sdk:assembleDebug

Regenerate Wails JS bindings

cd desktop && export PATH="$PATH:$(go env GOPATH)/bin" && wails generate module

Run this after adding or changing any exported method on App in desktop/app.go. Output goes to frontend-react/src/wailsjs/ — do not edit those files manually.


Architecture

Android App → Instrumentation SDK → ADB Tunnel → Go Backend → React Frontend → Wails Desktop Shell

Monorepo layout

Directory Module / Package Role
desktop/ git.achmad.dev/admin/droidscope/desktop Wails app — entry point, app.go exposes bound methods
backend-go/ git.achmad.dev/admin/droidscope/backend Go packages: ADB, device, logcat, network, storage, etc.
frontend-react/ Vite + React + TypeScript UI
android-sdk/ dev.achmad.droidscope Kotlin instrumentation SDK
scripts/ dev.sh, build.sh, download-adb.sh
docs/ DEVELOPMENT.md (setup + build guide), TODO.md (implementation status)

Go workspace

go.work links ./desktop and ./backend-go for local resolution. desktop/go.mod also has a replace directive — both are needed (go.work for IDE/build, replace for go mod tidy).

Wails ↔ React bridge

  • desktop/wails.json: "frontend:dir": "../frontend-react", "wailsjsdir": "../frontend-react/src"
  • Vite build.outDir is ../desktop/frontend/dist so Go's //go:embed works
  • Import bound methods from @/wailsjs/go/main/App in React

State model (frontend)

  • selectedDeviceId — which device the info panel is showing (can be anything)
  • profiledDeviceId — the active monitoring target for all feature panels (logcat, network, etc.)
  • These are separate concepts in app-store.ts (Zustand)

Active device scoping (all feature panels)

Every feature panel outside Device Management must:

  1. Import useActiveDevice from @/hooks/use-active-device
  2. Gate all polling/streaming behind isMonitoring
  3. Store per-device data via patchDeviceCache(deviceId, data) — never cleared on device switch
  4. Render <NoDeviceSelected /> when !isMonitoring

ADB binary resolution (runtime)

desktop/internal/adbembed/ — resolves in order: embedded binary → $ANDROID_HOME/platform-tools/adbadb on $PATH. Embed directive uses //go:embed all:bin (not //go:embed bin) because the placeholder file is hidden.

Static vs live device data

  • GetDeviceInfo(deviceId) — one-time fetch, ~20 static fields (model, OS version, ABI, etc.)
  • GetDeviceLiveStats(deviceId) — polled every 1 s (RAM, battery, thermal, storage, IP)
  • devices:changed Wails event — emitted every 1 s for the device list

Key conventions

  • Never use namespace TypeScript syntax — it conflicts with Wails-generated models.ts and erasableSyntaxOnly must stay off in tsconfig.app.json
  • shadcn/ui uses Base UI (not Radix UI) — DialogTrigger has no asChild prop; use controlled open state instead
  • tsconfig.app.json has no baseUrl; path alias @/*./src/* works via moduleResolution: bundler
  • Do not run go work sync — it fails for unpublished modules; the workspace + replace approach handles everything
  • Never commit anything under frontend-react/src/wailsjs/ — it is auto-generated