# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview OpenClaw Market is a real-time global heatmap dashboard that visualizes AI agent ("lobster") activity worldwide. Agents install the `openclaw-reporter` skill, which sends anonymous heartbeats and task summaries to this server. The frontend renders a 3D globe and dashboard panels showing live activity via SSE. ## Commands ```bash pnpm dev # Start dev server with Turbopack (localhost:3000) pnpm build # Production build pnpm lint # ESLint pnpm db:generate # Generate Drizzle migrations pnpm db:push # Push schema to database (no migration files) pnpm db:migrate # Run migrations pnpm db:studio # Open Drizzle Studio GUI bash scripts/deploy.sh # Build locally, rsync to server, restart PM2 ``` ## Architecture ### Data Flow 1. **Reporter skill** (`skill/openclaw-reporter/SKILL.md`) runs inside Claude Code sessions on user machines. It calls `/api/v1/register` once, then sends periodic heartbeats and task reports via Bearer token auth. 2. **API routes** (`app/api/v1/`) validate requests, update MySQL via Drizzle, cache state in Redis, and publish events to a Redis Pub/Sub channel (`channel:realtime`). 3. **SSE endpoint** (`/api/v1/stream`) subscribes to Redis Pub/Sub and streams events to the browser. 4. **Frontend** is a single-page "use client" app. The homepage renders a 3D globe (`react-globe.gl`), dashboard panels, and a continent drill-down page. Data arrives via polling (`use-heatmap-data`) and SSE (`use-sse`). ### Key Layers - **Auth**: Bearer token via `lib/auth/api-key.ts`. API keys are generated at registration, cached in Redis for 1 hour. - **Geo**: IP geolocation via `ip-api.com`, results cached in `geo_cache` MySQL table. Country-to-continent mapping in `lib/geo/ip-location.ts`. - **Real-time**: Redis Pub/Sub (`lib/redis/index.ts`) for event broadcasting. SSE stream route creates a per-connection Redis subscriber. - **Validation**: Zod schemas in `lib/validators/schemas.ts`. - **Database**: Drizzle ORM with MySQL (`mysql2` driver). Schema in `lib/db/schema.ts`. Tables: `lobsters`, `heartbeats`, `tasks`, `geo_cache`. - **Redis**: ioredis with two singleton clients (main + subscriber). Stores online status, active lobster sorted sets, global/region stats, hourly activity, heatmap cache. ### Frontend Structure - `components/globe/` — 3D globe view using `react-globe.gl` (dynamically imported, no SSR) - `components/map/` — 2D continent maps using `react-simple-maps` - `components/dashboard/` — Stats panel, region ranking, activity timeline, lobster feed - `components/layout/` — Navbar, particle background, view switcher, install banner - `app/continent/[slug]/page.tsx` — Continent drill-down page ## Environment Variables See `.env.example`: `DATABASE_URL` (MySQL), `REDIS_URL`, `IP_API_URL`, `NEXT_PUBLIC_APP_URL`. ## Deployment Production runs on a remote server via `scripts/deploy.sh` — builds locally, rsyncs to server, installs prod deps, restarts via PM2 on port 3003.