Files
WoMenQuNaJu/CLAUDE.md
2026-02-13 15:43:40 +08:00

13 KiB

CLAUDE.md

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

Project Overview

"点线得面" - A WeChat Mini Program for collaborative meeting point selection. Users create rooms, share with friends, each member adds their location, and the system calculates the optimal meeting venue based on everyone's coordinates. Maximum 8 members per room, and rooms expire after 30 days.

Architecture: WeChat Mini Program frontend + WeChat Cloud Functions backend + MeetSpot Python API (external service)

Repository Structure

WoMenQuNaJu/
├── miniprogram/          # WeChat Mini Program frontend
│   ├── pages/            # Page components (index, create-room, room, result)
│   ├── app.js/json/wxss  # Application entry
│   └── images/           # Static assets
├── cloudfunctions/       # WeChat Cloud Functions (Node.js)
│   ├── calculateMeetSpot/     # Core: calls MeetSpot API to calculate venues
│   ├── createRoom/            # Create a new room
│   ├── joinRoom/              # Add member to room (max 8 people)
│   ├── updateLocation/        # Update current user's location
│   ├── updateMemberLocation/  # Update test member's location (dev only)
│   ├── updateRoomInfo/        # Update room metadata
│   ├── removeMember/          # Remove member from room
│   ├── deleteRoom/            # Delete entire room
│   ├── cleanExpiredRooms/     # Scheduled: delete rooms older than 30 days
│   ├── addTestMember/         # Add test member (dev only)
│   └── getOpenId/             # Get user's WeChat OpenID
└── MeetSpot/             # Python FastAPI backend (has its own CLAUDE.md)

Key Insight: The WeChat Mini Program is a lightweight frontend/coordinator. The heavy lifting (geocoding, POI search, venue ranking) is delegated to the MeetSpot FastAPI service via the calculateMeetSpot cloud function.

WeChat Mini Program Development

Setup

# Install WeChat Developer Tools
# Download from: https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

# Open project in WeChat Developer Tools
# Project directory: d:\download\WoMenQuNaJu
# AppID: wxb7e6344198f6526f (from project.config.json)

Cloud Functions: Each function in cloudfunctions/ needs dependencies installed separately:

# For cloud functions that use axios (like calculateMeetSpot)
cd cloudfunctions/calculateMeetSpot
npm install

# Repeat for other functions with package.json
cd ../createRoom
npm install

Deploy Cloud Functions: Use WeChat Developer Tools GUI to upload cloud functions, or use CLI:

# Upload a single cloud function
miniprogram-ci cloud uploadFunction --functionName calculateMeetSpot

Testing

Local Testing: Use WeChat Developer Tools simulator. The simulator supports:

  • Cloud function calls
  • Cloud database operations
  • Location services (mocked)

Backend URL Configuration:

  • calculateMeetSpot/index.js:78 contains BACKEND_URL environment variable
  • Default: https://meetspot.onrender.com (production MeetSpot API)
  • For local testing: Set cloud function env var to http://localhost:8000 (requires ngrok or similar for Mini Program to reach local machine)

Data Model

Cloud Database Collection: rooms

Data Retention: Rooms are automatically deleted 30 days after creation. A scheduled cloud function cleanExpiredRooms runs periodically to clean up expired data.

{
  _id: "auto-generated",
  _openid: "creator's openid",
  createdAt: ServerDate,
  expireTime: Date,  // Auto-delete 30 days after creation
  status: "active" | "calculating" | "calculated",
  name: "聚会名称",
  meetTime: "2026-02-10 18:00",
  keywords: "咖啡馆",
  requirements: "parking, quiet",
  members: [
    {
      openid: "wx-openid",
      avatarUrl: "https://...",
      nickName: "用户昵称",
      location: {
        lng: 116.32,
        lat: 39.99,
        address: "北京大学",
        name: "北京大学"
      },
      joinedAt: Date,
      isTestMember: false  // true for dev test members
    }
  ],
  result: {
    success: true,
    venues: [...],
    center: { lat: 39.99, lng: 116.32 },
    html_url: "/workspace/js_src/recommendation_xxx.html"
  },
  lastCalculateTime: ServerDate,
  lastCalculatedMembers: "openid1_lat_lng,openid2_lat_lng,..."  // Snapshot for duplicate detection
}

Member Limit: Maximum 8 members per room. Enforced in joinRoom cloud function.

Architecture Patterns

Status Locking Pattern

Problem: Multiple users clicking "Calculate" simultaneously could trigger duplicate API calls.

Solution: calculateMeetSpot uses database-level status locking:

// 1. Check if status is "calculating" (early return if locked)
if (data.status === 'calculating') return { msg: '正在计算中' }

// 2. Acquire lock
await db.collection('rooms').doc(roomId).update({ status: 'calculating' })

// 3. Call backend API
const result = await axios.post(BACKEND_URL, ...)

// 4. Release lock and save result
await db.collection('rooms').doc(roomId).update({
  status: 'calculated',
  result: result.data
})

Exception Handling: If API call fails, the catch block releases the lock by setting status: 'active'.

Duplicate Calculation Prevention

Problem: Users might click "Calculate" multiple times without changing member locations.

Solution: calculateMeetSpot/index.js:43-61 compares current member positions against lastCalculatedMembers snapshot:

const currentSnapshot = validMembers
  .map(m => `${m.openid}_${m.location.lat}_${m.location.lng}`)
  .sort()
  .join(',')

if (currentSnapshot === data.lastCalculatedMembers) {
  return { isDuplicate: true, existingResult: data.result }
}

Real-time Synchronization

Pattern: Database Watch API for live updates

Implementation: miniprogram/pages/room/room.js:125-179

db.collection('rooms').doc(roomId).watch({
  onChange: snapshot => {
    // Sync room state, member list, calculation status
    // Auto-navigate to result page when status changes from 'calculating' to 'calculated'
  }
})

Critical Detail: Uses previousStatus tracking to only auto-navigate when calculation just finished, preventing navigation loops when users return to the room page.

Test Member System

Purpose: Allow room creators to add mock members for testing without needing multiple WeChat accounts.

Identification: Test members have isTestMember: true and openid format test_<timestamp>_<random>

Special Handling:

  • addTestMember: Creates member with random location (Beijing area)
  • updateMemberLocation: Allows creator to update test member locations
  • removeMember: Can delete test members
  • UI shows "测试" badge and allows creator to edit their locations

Cloud Functions

Core Function: calculateMeetSpot

Responsibility: Bridge between Mini Program and MeetSpot API

Flow:

  1. Validate: At least 2 members with locations
  2. Check: Duplicate calculation detection
  3. Lock: Set status to calculating
  4. Transform: Extract { lng, lat, address, name } from members
  5. Call: POST to BACKEND_URL/api/miniprogram/calculate
  6. Store: Save result to database, update status to calculated

Environment Variables: Set in WeChat Cloud Console

  • BACKEND_URL: MeetSpot API endpoint (default: https://meetspot.onrender.com)

Timeout: 30 seconds (axios timeout). MeetSpot API typically responds in 3-15 seconds.

Database Mutating Functions

Function Mutation Permission Check
createRoom Add document to rooms Anyone (creator = caller's openid)
joinRoom Push to members array Anyone (duplicate check by openid)
updateLocation Update member's location in array Own openid only
updateMemberLocation Update test member location Creator only
updateRoomInfo Update room metadata Creator only (checked via _openid)
removeMember Remove from members array Self-exit OR creator removing others
deleteRoom Delete entire document Creator only

Security Note: Cloud Functions automatically add _openid field (caller's WeChat ID) to database writes. Permission checks compare wxContext.OPENID against stored _openid.

MeetSpot Backend Integration

The MeetSpot/ subdirectory is a separate Python/FastAPI project. See MeetSpot/CLAUDE.md for details.

Key Integration Point: calculateMeetSpot cloud function calls POST /api/miniprogram/calculate endpoint.

Expected Request:

{
  "locations": [
    { "lng": 116.32, "lat": 39.99, "address": "北京大学", "name": "北京大学" }
  ],
  "keywords": "咖啡馆",
  "requirements": "parking, quiet"
}

Expected Response:

{
  "success": true,
  "venues": [ /* Array of ranked venues */ ],
  "center": { "lat": 39.99, "lng": 116.32 },
  "html_url": "/workspace/js_src/recommendation_xxx.html"
}

To run MeetSpot locally:

cd MeetSpot
python web_server.py
# Backend will be at http://localhost:8000

Common Development Tasks

Adding a New Cloud Function

  1. Create directory: cloudfunctions/myFunction/
  2. Add index.js:
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })

exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  // Your logic here
  return { success: true }
}
  1. Add package.json if using npm dependencies
  2. Install dependencies: npm install (in function directory)
  3. Upload via WeChat Developer Tools

Modifying Room Schema

Important: WeChat Cloud Database is schemaless, but for consistency:

  1. Update createRoom/index.js for new fields in initial data
  2. Add migration logic in calculateMeetSpot or other functions if transforming existing data
  3. Update TypeScript interfaces if using typed Mini Program (this project uses plain JS)

Changing Keywords/Requirements Options

Keywords Picker: miniprogram/pages/room/room.js:10

keywordOptions: ['咖啡馆', '餐厅', '公园', ...]

Requirements: Free-text input, no predefined options. MeetSpot API parses natural language.

Debugging Cloud Functions

Method 1: WeChat Developer Tools Console

  • Right-click function → "Upload and Debug"
  • Use console.log() - logs appear in Cloud Development Console

Method 2: Local Cloud Function Emulation

  • Install miniprogram-ci
  • Use npx miniprogram-ci cloud emulator

Performance Considerations

Cold Start: Cloud functions have ~500ms-2s cold start. First calculation in a room may feel slow.

Database Watch: Each page maintains one watch connection. WeChat limits 5 concurrent watches per user. Close watches in onUnload().

Calculation Time: Typical flow takes 5-15 seconds:

  • Cloud function startup: 0.5-2s
  • MeetSpot API call: 3-12s (includes geocoding, POI search, ranking)
  • Database write: 0.1-0.5s

Optimization: Duplicate calculation prevention saves ~90% of redundant API calls.

Deployment

Mini Program

  1. Update version in WeChat Developer Tools
  2. Click "Upload" → Enter version number and description
  3. Submit for review in WeChat Public Platform
  4. After approval, release to production

Cloud Functions

Individual Upload: Right-click function → "Upload and Deploy: Cloud Installation Dependencies"

Batch Upload: Cloud Development Console → Cloud Functions → Batch upload

CI/CD: Use miniprogram-ci for automated deployment:

miniprogram-ci upload --project /path/to/project \
  --appid wxb7e6344198f6526f \
  --version 1.0.0 \
  --desc "Update description"

Debugging Common Issues

Issue Cause Solution
"未找到云函数" Function not uploaded Upload via Developer Tools
"正在计算中" stuck Lock not released after error Manually set status: 'active' in database
Empty result page BACKEND_URL unreachable Check cloud function logs, verify MeetSpot API is running
Location picker fails Missing permission Check app.jsonpermissionscope.userLocation
Watch connection lost Network interruption Page will auto-reconnect on next data change
"至少需要2人" error Only 1 member has location Add more member locations or use test members

Logs: Cloud Development Console → Cloud Functions → Function logs (search by requestId)

Code Style

  • JavaScript: 4-space indent, ES6+ syntax, no semicolons (Mini Program convention)
  • Cloud Functions: Use async/await, avoid callbacks
  • Naming: camelCase for variables/functions, PascalCase for pages/components
  • Comments: Chinese for user-facing strings, English for technical comments acceptable