← PlantDex

How it's built

Architecture

How PlantDex is put together

PlantDex is a discovery index and UI layer over the Trefle plant API — not a social app or personal collection manager. The frontend lives on Vercel; the API runs on AWS (API Gateway, Lambda, DynamoDB, Secrets Manager) and talks to Trefle on your behalf.

System architecture

Requests flow browser → API Gateway → Lambda. Reads hit a DynamoDB cache when possible; the Trefle token never leaves Secrets Manager / Lambda.

Next.js on Vercel

Browser

  • Search / profiles / compare
  • Native-range globe (Photon)
  • Report & correction forms

HTTPS · NEXT_PUBLIC_PLANTDEX_API_URL

AWS HTTP API

API Gateway

  • GET /search · /plants/{slug} · /similar
  • POST /plants/{slug}/report · /corrections

Lambda integration

Python 3.12

Lambda

  • Normalize Trefle payloads
  • Similarity querying
  • Proxy writes to Trefle

Response cache + TTL

DynamoDB

  • Search / profile / similar keys
  • Cuts repeat Trefle calls

plantdex/trefle-token

Secrets Manager

  • Trefle API token
  • Never sent to the browser

Outbound plant data

trefle.io

Trefle API

  • Community-sourced plant metadata
  • Source of truth for PlantDex

What each layer does

Frontend

Next.js App Router UI for search, profiles, related plants, compare (localStorage tray only), distribution globe via Photon geocoding, and Trefle feedback forms.

Backend

Python Lambda package in src/ normalizes Trefle payloads, runs similarity helpers, caches responses, and proxies report/correction writes.

Caching

DynamoDB stores JSON responses keyed by request shape with TTL, which keeps Trefle traffic down and makes profile related-plant sections feel snappier on repeat views.

Data source

Trefle is community-sourced and imperfect. PlantDex surfaces that clearly and lets users send reports/corrections upstream without handling API tokens in the browser.

Backend APIs

Read endpoints can be run live against the real backend — edit the inputs and hit Run API to inspect raw JSON. Report and correction endpoints are example-only so Trefle doesn’t get accidental playground traffic.

GET/search

Search plants by common or scientific name.

Request URL

GET https://lyot4yhfu8.execute-api.us-west-2.amazonaws.com/search?query=blueberry&max_results=3&image_only=false
GET/plants/{slug}

Fetch a full plant profile for a Trefle slug.

Request URL

GET https://lyot4yhfu8.execute-api.us-west-2.amazonaws.com/plants/vaccinium-corymbosum
GET/similar

Return related plants using a similarity basis.

Request URL

GET https://lyot4yhfu8.execute-api.us-west-2.amazonaws.com/similar?query=vaccinium-corymbosum&basis=genus&max_results=3&image_only=false
POST/plants/{slug}/reportExample only

Proxy an error report to Trefle (token stays on the server).

Live run is disabled here so Trefle isn’t flooded by playground traffic. Use the profile page form when you truly need to report something.

Example request

POST /plants/{slug}/report

{
  "notes": "The maximum height on this record looks incorrect.",
  "species_id": "vaccinium-corymbosum"
}

Example JSON response

{
  "ok": true,
  "type": "report",
  "species_id": "vaccinium-corymbosum",
  "trefle": {
    "id": 9,
    "record_type": "Species",
    "warning_type": "report",
    "change_status": "pending",
    "notes": "The maximum height on this record looks incorrect."
  }
}
POST/plants/{slug}/correctionsExample only

Proxy a field correction to Trefle for peer review.

Live run is disabled here so Trefle isn’t flooded by playground traffic. Use the profile page form for real corrections.

Example request

POST /plants/{slug}/corrections

{
  "notes": "Updating observations from a trusted reference.",
  "source_type": "external",
  "source_reference": "https://example.org/botany-source",
  "species_id": "vaccinium-corymbosum",
  "correction": {
    "observations": "Native to eastern North America"
  }
}

Example JSON response

{
  "ok": true,
  "type": "correction",
  "species_id": "vaccinium-corymbosum",
  "trefle": {
    "id": 8,
    "record_type": "Species",
    "change_status": "pending",
    "change_type": "update",
    "notes": "Updating observations from a trusted reference.",
    "correction": {
      "observations": "Native to eastern North America"
    }
  }
}