Greenlens/CLAUDE.md

4.0 KiB

CLAUDE.md

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

Commands

Mobile App (Expo)

npm install          # Install dependencies
npm run start        # Start Expo dev server (offline mode)
npm run android      # Start on Android
npm run ios          # Start on iOS
npm run test         # Run Jest tests

Server (Express)

cd server
npm install
npm run start        # Start Express server
npm run rebuild:batches   # Rebuild plant catalog from batch constants
npm run diagnostics       # Check duplicates and import audits

Production Builds (EAS)

npx eas-cli build:version:set -p ios    # Bump iOS build number
npx eas-cli build -p ios --profile production
npx eas-cli submit -p ios --latest      # Submit to TestFlight

Architecture

Mobile App

Expo Router with file-based routing. Entry point is app/_layout.tsx.

  • app/(tabs)/ — Tab navigation: Home (index.tsx), Search, Profile
  • app/scanner.tsx — Plant scan modal
  • app/lexicon.tsx — Plant encyclopedia
  • app/plant/ — Plant detail screens
  • app/auth/ — Login / Signup screens
  • app/onboarding.tsx — First-launch onboarding

Global state lives in context/AppContext.tsx (plants, user, billing, language).

Services Layer (Mobile)

  • services/storageService.ts — AsyncStorage persistence for user plants
  • services/plantRecognitionService.ts — Calls /v1/scan on backend
  • services/plantDatabaseService.ts — Local static plant data
  • services/authService.ts — JWT auth against backend
  • services/backend/backendApiClient.ts — HTTP client for all /v1/* calls
  • services/backend/mockBackendService.ts — In-app mock if EXPO_PUBLIC_BACKEND_URL is not set

Backend (Express — server/)

Single server/index.js with all routes. Libs in server/lib/:

  • sqlite.js — SQLite wrapper (openDatabase, run, get, all)
  • plants.js — Plant catalog CRUD + semantic search
  • auth.js — JWT-based signup/login
  • billing.js — Credits, idempotency, Stripe webhooks
  • openai.js — Plant identification + health analysis via OpenAI
  • storage.js — MinIO/S3 image upload (uploadImage, ensureStorageBucket)

Key env vars for server:

PLANT_DB_PATH        # SQLite file path (default: server/data/greenlns.sqlite)
OPENAI_API_KEY
STRIPE_SECRET_KEY
JWT_SECRET
MINIO_ENDPOINT / MINIO_ACCESS_KEY / MINIO_SECRET_KEY / MINIO_BUCKET / MINIO_PUBLIC_URL

Landing Page (greenlns-landing/)

Next.js 16 app with output: 'standalone' for Docker. Runs independently from the mobile app.

Has its own docker-compose.yml that spins up:

  • Next.js app (Landing Page)
  • PostgreSQL 16 (persistent DB for the backend)
  • MinIO (persistent image storage)
  • Nginx (reverse proxy + SSL)

Infrastructure Plan

Current state: Server runs on Railway with SQLite (ephemeral).

Target state (not yet migrated):

  • Express Server moves OFF Railway → runs on the landing page server via docker-compose.yml
  • PostgreSQL + MinIO replace SQLite + Railway hosting entirely

When migrating to PostgreSQL (do all of these together):

  1. Remove server/lib/sqlite.js and server/data/ entirely
  2. Remove Railway service for the Express server (no longer needed)
  3. Add pg package to server/package.json
  4. Replace all SQLite calls with pg and DATABASE_URL env var
  5. Change all SQL placeholders from ? to $1, $2, ... (SQLite → PostgreSQL syntax)
  6. Add Express server as a service in greenlens-landing/docker-compose.yml
  7. Use JSONB columns in PostgreSQL for nested data (e.g. careInfo, categories) instead of serialized strings — enables fast querying and filtering directly on JSON fields

Key Patterns

  • SQL placeholders: SQLite uses ?, PostgreSQL uses $1, $2, ... — important when migrating
  • Translations: utils/translations.ts supports de / en / es
  • Colors: constants/Colors.ts with light/dark mode tokens
  • Image URIs: App sends base64 to /v1/upload/image, gets back a public MinIO URL