OctoWiki
Memory Appendix

Vendor Architecture

Octopus has TWO distinct vendor concepts — topup vendors (suppliers) and the Grasshopper vendor (sales surface). All gift card products live under vendor.code='

Source memory file: project_vendor_architecture.md · Category: Project / investigation This is a verbatim dump of Claude's persistent memory for the Octopus project. Rendered inside a code block so nothing is altered.

---
name: project-vendor-architecture
description: "Octopus has TWO distinct vendor concepts — topup vendors (suppliers) and the Grasshopper vendor (sales surface). All gift card products live under vendor.code='GH'."
metadata: 
  node_type: memory
  type: project
  originSessionId: b0e6c877-5dbd-4595-8081-bf10f1463e62
---

Octopus has **two distinct vendor concepts** that share the same `vendors` table but play completely different roles in the data model:

**1. Topup vendors** (DT One, SEAGM, Tillo, Bamboo, Runa, etc. — vendor IDs like 4, 5)
- Own `topup_products` + `topup_variants` (and `esim_products` + `esim_variants` for eSIM)
- These are the **upstream suppliers** — vendors we buy from
- `topup_variants.vendor_id` points here

**2. Grasshopper vendor** (`vendor.code = 'GH'`, single row)
- Owns **ALL** `products` + `vendor_products`
- This is the **sales surface** — what customers see as "Octopus gift cards"
- `vendor_products.vendor_id` is **always** GH for gift card rows

**The pipeline:**
```
topup_variant (vendor 4/5/etc) ──[push to GH]──▶ product + vendor_product (vendor=GH)
```

`pushVariantToGrasshopper` creates a `product` row + a `vendor_product` row under vendor=GH for each topup_variant. The linkage is soft — idempotency by `(vendor_id=GH, vendor_product_name, min_denomination)`, no FK back to `topup_variants.id`.

**Why:** Customer-facing wording must look like Octopus does everything itself (see [[feedback-no-vendor-in-customer-facing]]). The GH-vendor model enforces that — every product the customer sees is "from Grasshopper" by data structure.

**How to apply:**
- When asked about "demo products in vendor_products with bad names", search **vendor.code='GH'**, not the topup vendor IDs.
- Wiping a topup vendor (e.g. DTONE / id=4) does **not** clean up the GH-side gift cards it produced — those persist with `vendor_id=GH` and no remaining linkage.
- "Vendor for the gift card" = always GH. "Vendor for the topup" = the upstream supplier.
- `recharges.vendor_id` points to the topup vendor; gift card orders / `order_items.vendor_id` point to GH.

Related: [[project-shopify-upgrade-2026-04]] (Shopify integration uses GH vendor's products).